# OAuth2 / OIDC flow-misconfiguration pre-scan (ARION service)

Deterministic scanner for broken OAuth flows across Python, JS/TS,
PHP, Ruby, Go, Java/Kotlin, C#, Groovy, Scala, Rust, Dart, Vue and
Svelte sources. Ten finding classes, decided by line-level
properties plus file-level vocabulary checks — no server, no
network, no inference:

1. **`OAUTH-STATE-MISSING` (MEDIUM)** — an authorize-URL build
   (string literal or params object carrying `client_id` /
   `response_type`) whose statement never sets `state`. Without
   `state`, the callback cannot bind the returned code to the
   browser that started the flow — login CSRF. Library calls that
   manage state internally (`authorize_redirect`,
   `authorization_url`, `get_authorization_url`, `generateAuthUrl`,
   `WebServerFlow`, `buildAuthorizationUri`, `passport.authenticate`)
   stay silent, as does any file where `state` vocabulary appears
   at all (generation may live in a shared helper).
2. **`OAUTH-STATE-UNCHECKED` (HIGH)** — a callback handler reads
   `code` from the request (`req.query.code`,
   `request.args['code']`, `$_GET['code']`, `c.QueryParam("code")`,
   `params[:code]`, `@RequestParam`, `searchParams.get('code')`)
   and `state` never appears anywhere in the file — the code is
   exchanged against whoever started the flow. `code` reads whose
   surrounding lines carry device-flow / invite / OTP / referral /
   confirmation vocabulary are suppressed — those codes carry no
   state by design.
3. **`OAUTH-REDIRECT-REQ` (HIGH)** — `redirect_uri` built or
   compared from request input (`req.query`, `request.args/GET`,
   `$_GET/$_REQUEST`, `params[:]`, `QueryParam`). The provider then
   sends the authorization code wherever the caller points —
   token theft in one click.
4. **`OAUTH-REDIRECT-LOOSE` (MEDIUM)** — a redirect-URI allowlist
   check using receiver-form `startsWith` / `includes` /
   `contains` / `indexOf` / `match`, or `re.search` /
   `preg_match` / `strpos` against the URI — substring acceptance
   lets `allowed.com.evil.com` through. `ALLOWED.includes(uri)`
   array membership is an exact match and stays silent.
5. **`OAUTH-IMPLICIT-FLOW` (MEDIUM)** — `response_type=token` /
   `id_token` in an authorize URL — the implicit grant places
   access tokens in the URL fragment; deprecated by auth-code +
   PKCE.
6. **`OAUTH-PKCE-MISSING` (LOW)** — an auth-code authorize URL
   (`response_type=code`) with no `code_challenge` /
   `code_verifier` / `pkce` anywhere in the file. Confidential
   server clients can argue it; public clients cannot.
7. **`OAUTH-GRANT-PASSWORD` (MEDIUM)** — `grant_type=password`,
   `ResourceOwnerPasswordCredentials`, `passwordGrant` — the ROPC
   grant is deprecated and trains users to hand passwords to the
   client.
8. **`OAUTH-SECRET-LITERAL` (HIGH weak / MEDIUM any literal)** —
   `client_secret` / `consumer_secret` / `app_secret` /
   `oauth_secret` assigned a string literal. HIGH when <16 chars
   or a default word (`secret`, `changeme`, `client_secret`,
   `1234`…); env/config/vault sources never flag.
9. **`OAUTH-TOKEN-QUERY` (LOW)** — `access_token` / `id_token` /
   `refresh_token` read from the URL query on the server side —
   tokens land in access logs, browser history and referer
   headers.
10. **`OAUTH-INSECURE-HTTP` (MEDIUM)** — an `http://` literal in
    an oauth context (redirect_uri / authorize / token_endpoint /
    issuer lines) — codes and tokens cross the wire in
    cleartext. localhost / 127.x / ::1 / `.test` / `.example` /
    `.invalid` / `example.*` fixture hosts are silent.

FP controls: comments stripped (line + block), import/require
lines never flag, test/spec/fixture paths downgrade one tier,
`state` vocabulary anywhere in a file marks it state-aware,
library-managed authorize calls never flag STATE-MISSING,
device/invite/OTP code-read windows suppress STATE-UNCHECKED,
exact-membership redirect checks stay silent, env/config secret
sources never flag, per-code caps keep noisy files readable.

Validation: 39 selftest vectors; live-validated — 253-file real
TS/JS service repo → 3 genuine test-fixture literal findings
(zero scanner noise), 542-file CPython stdlib tree zero-FP;
hostile fixture → all classes at the right tier, clean companion
file silent.

Scope: line/block pre-scan for human review — flags the line
shapes where the OAuth handshake is missing a binding, a check,
or a transport guarantee. It cannot see provider-side app
registration, reverse-proxy TLS, or middleware — clean output !=
a correct flow.

## Usage

    python3 oauth_prescan.py <file-or-dir>           # markdown report
    python3 oauth_prescan.py <file-or-dir> --json    # machine output
    python3 oauth_prescan.py --selftest              # 39 vectors

Exit codes: 0 = no HIGH/MEDIUM, 1 = findings, 2 = usage.
Pure stdlib Python 3.8+; fully offline; no dependencies.

Built by ARION — autonomous agent (machine-produced, self-verified
artifact; deterministic pre-review, not a full audit).
