This document records early design decisions that classifier and detector issues can reference. Decisions are intentionally conservative: SessionScope should present evidence clearly without overstating what static analysis can prove.
Environment-specific settings are represented as dynamic evidence unless the production behavior is statically clear.
Rules:
- Literal, unconditional insecure settings may produce
high_confidence_misconfiguration. - Environment-conditioned or computed settings set
dynamic = true, use lower confidence, and usually producedynamic_review_required. - If a production branch is statically clear, classifiers may evaluate that branch directly.
- If production behavior is not statically clear, reports should show the sanitized expression and ask a reviewer question.
Example dynamic cookie evidence:
{
"lifecycle_stage": "store",
"detector_id": "cookie.attribute",
"confidence": "medium",
"excerpt": "secure: process.env.NODE_ENV === \"production\"",
"dynamic": true,
"framework_default": false
}Example finding shape:
{
"category": "dynamic_review_required",
"severity": "medium",
"title": "Cookie Secure attribute depends on environment",
"description": "The cookie appears to set Secure only when NODE_ENV is production.",
"reviewer_question": "Can this deployment guarantee NODE_ENV is production for externally reachable environments?"
}Example dynamic JWT validation evidence:
{
"lifecycle_stage": "validate",
"detector_id": "jwt.verify.options",
"confidence": "medium",
"excerpt": "audience: config.auth.expectedAudience",
"dynamic": true,
"framework_default": false
}Framework defaults are evidence, not proof of application behavior, unless the framework version and active configuration are deterministically known.
Rules:
- Default-derived evidence sets
framework_default = true. - Findings based primarily on defaults should use
framework_default_assumedordynamic_review_required. - Default-derived evidence should not produce high-confidence findings unless local source/config proves the effective behavior.
- Reports should identify the framework and the assumption behind the default.
Example Express-style default assumption:
{
"lifecycle_stage": "store",
"detector_id": "express.cookie.default",
"confidence": "low",
"excerpt": "cookie options omit sameSite; Express default assumed",
"dynamic": false,
"framework_default": true
}Example Django/FastAPI-style default assumption:
{
"category": "framework_default_assumed",
"severity": "low",
"title": "Cookie setting depends on framework default",
"description": "The local code does not set the attribute directly; behavior appears to depend on the framework default.",
"reviewer_question": "Which framework version and deployment settings are active in production?"
}Confidence describes the strength of evidence, not impact.
Rules:
high: direct local evidence with literal or structurally deterministic behavior.medium: strong pattern evidence with some config, environment, or framework indirection.low: heuristic, partial, or framework-default-dependent evidence.- High-confidence findings require direct evidence of misconfiguration.
- Missing evidence generally becomes
dynamic_review_requiredor another review-required finding unless detector coverage is complete enough to state the absence precisely.
Finding category guidance:
- Use
high_confidence_misconfigurationfor direct, deterministic unsafe settings. - Use
missing_validation_evidencewhen validation code is present but a specific check, such as issuer or audience, is not observed nearby. - Use
lifecycle_gapwhen evidence shows part of the lifecycle but no linked counterpart, such as refresh without rotation evidence. - Use
dynamic_review_requiredwhen behavior depends on runtime config, environment, or unresolved control flow. - Use
framework_default_assumedwhen the finding depends primarily on a framework default.
SessionScope will not share an intermediate representation with AuthMap in
v0.1.0.
Rules:
- SessionScope owns its token lifecycle inventory schema for this milestone.
- The claims capability records JWT validation, identity-claim, and boundary evidence as source-bound inventory and reviewer questions; it is not a full authorization graph engine.
- The model should align conceptually with AuthMap-style evidence records: stable IDs, source locations, sanitized excerpts, confidence, and reviewer questions.
- Future AuthMap/rulepath interoperability should be designed as an explicit integration boundary rather than implied by claim inventory fields.
- Shared IR work should be revisited only when a concrete integration requirement exists.
- Detectors should keep token lifecycle evidence separate from authorization policy evidence until such an integration is designed.
Client-side cookie clearing is lifecycle evidence, but it is not proof that the server-side session, refresh token, or provider token was revoked.
Rules:
- Detectors may emit
revokeevidence for cookie deletion APIs such as ExpressclearCookie, Next.jscookies().delete, FastAPIdelete_cookie, and Djangodelete_cookie. - Cookie clear evidence uses
logout.cookie_clearand should be treated as a browser-side action only. - Server-side invalidation evidence should use more specific detector IDs such
as
logout.session_destroy,logout.token_revoke, orlogout.provider_revoke. logout.handleridentifies logout control flow, but it does not satisfy server-side revocation checks by itself.- Lifecycle classifiers may ask a reviewer question when logout only clears a cookie and no linked server-side revocation evidence is present.
- Cookie deletion should use the same static
pathanddomainattributes used when the cookie was set; mismatches or omitted set attributes are review-required lifecycle context. - Provider and wrapper revocation calls are static-analysis context only; they should stay medium or low confidence unless local source proves the exact backend behavior.
Refresh-token rotation and reuse handling require server-side lifecycle evidence. Seeing a refresh handler or provider SDK call is useful context, but it is not proof that previous refresh tokens are invalidated.
Rules:
- Refresh handlers, token generation, storage, validation, expiry, rotation, reuse detection, and revocation should be emitted as lifecycle evidence when statically visible.
- Old-token invalidation, mark-used updates, denylist writes, token-family revocation, and provider revoke calls may satisfy server-side revocation checks when linked to the same refresh-token path.
- Refresh-token evidence is linked by bounded source context or explicit safe
local keys, not by the common
refresh_tokendisplay name alone. - Provider-managed refresh behavior should be represented as dynamic review context unless local source proves the provider rotates or revokes previous refresh tokens.
- Clearing a refresh cookie remains client-side evidence only; it does not satisfy refresh-token rotation or revocation checks.
Session fixation review depends on framework behavior, middleware ordering, and the exact point where an authenticated or elevated identity is bound to a session. Static evidence should identify likely transition points and visible rotation, but it should not claim exploitability from missing local evidence alone.
Rules:
- Login, sign-in, auth callback, impersonation, role elevation, admin promotion, and permission-change handlers may emit session transition evidence.
- Explicit session regeneration, session-key cycling, and clear-and-reissue cookie-session patterns may satisfy nearby transition review when linked by local source context.
- Recognized Django
login(request, user),auth_login(request, user), andrequest.session.cycle_key()calls are acceptable framework/default regeneration evidence when visible in source. - Missing regeneration near a login or privilege transition should produce a
medium-severity
dynamic_review_requiredfinding with a reviewer question, not a high-confidence misconfiguration. - Logout-only handlers and cookie deletion evidence should not create session fixation findings.
Token reuse across services, audiences, environments, or frontend/backend boundaries depends on deployment configuration and provider policy. Static source evidence should preserve boundary hints and ask targeted reviewer questions when reuse is plausible, but it should not turn ambiguous reuse into a definitive exploit finding.
Rules:
- Boundary evidence may include issuer, audience, service, environment, tenant, provider, scope, and frontend/backend trust-boundary hints when visible.
- JWT missing issuer or audience validation remains a JWT validation finding; trust-boundary reuse findings ask whether a token is reused outside its intended boundary.
- Inbound bearer/API-key evidence forwarded outbound without visible
audience/service/scope evidence should be
dynamic_review_required. - Same token names spanning frontend/backend paths or multiple environment hints should be review-required unless source-bound evidence proves separation.
- Provider and wrapper-managed token handling should remain review-required unless local source or config shows the effective audience, service, tenant, and scope policy.
Cookie posture findings should distinguish deterministic unsafe settings from runtime policy questions.
Rules:
- Explicit cookie lifetime greater than 30 days is a high-confidence posture finding when Max-Age or a relative Expires duration is statically derivable.
- Absolute far-future Expires values are review-required unless the local source also exposes a derivable relative duration.
- Explicit broad Domain scope and explicit
Path=/on session-like or signed cookies are high-confidence findings when the values are directly visible. SameSite=Nonewithout Secure remains high-confidence.SameSite=Nonewith Secure is review-required because cross-site cookie delivery may be intentional.- Dynamic cookie options and framework-default behavior should remain
dynamic_review_requiredorframework_default_assumed. - Browser storage of session-like tokens should reuse token storage evidence and must not introduce raw token or cookie values into reports.
SessionScope reports should be useful before they become merge blockers. Advisory mode remains the default for CLI and GitHub Action usage. Enforce mode is opt-in and evaluates already-rendered findings after reports have been written.
Rules:
mode = "advisory"exits successfully when scanning and report writing succeed, even if findings are present.mode = "enforce"exits nonzero only for findings that match the configured policy.- The default enforcement threshold is
highseverity across all categories. Teams can tighten tomedium,low, orinfoafter reviewing advisory output. - Category filters use model JSON names, such as
high_confidence_misconfigurationanddynamic_review_required. - Exact finding IDs in
include_finding_idsblock even when they are present in a baseline. Exact IDs inexclude_finding_idsnever block. - Baseline support is read-only suppression of finding IDs from an existing
JSON report with a top-level
findingsarray. Full baseline creation and lifecycle management remain separate. - Missing or malformed baseline files are configuration errors whenever a baseline is explicitly supplied.
The v0.2 edge-case hardening checks fit the existing five finding categories.
No new finding category or SARIF rule ID is added in this round, and the scan
report schema remains 0.5.0.
Explicit audit decisions:
- P2.3
jwt_alg_confusion_signal: no newcryptographic_trust_violationcategory. Literal mixed algorithm families remainhigh_confidence_misconfiguration; key-family ambiguity remainsdynamic_review_required. - P2.4 JWT header-trust checks: no new
cryptographic_trust_violationcategory. Header-drivenjku,x5u, and embedded-JWK trust remainsdynamic_review_requiredbecause source evidence cannot prove live URL, certificate, JWKS, or provider allow-list behavior. - P3.1 OAuth artifact type: keep the dedicated
oauth_auth_code_flowartifact type. Reusing a token artifact would blur flow-construction evidence with issued-token lifecycle evidence.
Category mapping for new v0.2 checks:
| Check ID | Category mapping |
|---|---|
cookie_host_prefix_path_violation |
high_confidence_misconfiguration for literal violations; dynamic_review_required for dynamic Path evidence |
cookie_host_prefix_domain_violation |
high_confidence_misconfiguration for literal Domain evidence; dynamic_review_required for dynamic Domain evidence |
cookie_host_prefix_secure_violation |
high_confidence_misconfiguration for missing/false literal Secure; dynamic_review_required for dynamic/default Secure evidence |
cookie_secure_prefix_secure_violation |
high_confidence_misconfiguration for missing/false literal Secure; dynamic_review_required for dynamic/default Secure evidence |
cookie_samesite_none_without_secure |
high_confidence_misconfiguration |
cookie_samesite_none_dynamic_secure |
dynamic_review_required |
cookie_samesite_none_default_secure |
framework_default_assumed |
cookie_samesite_none_cross_site_review |
dynamic_review_required |
cookie_partitioned_review |
dynamic_review_required |
cookie_domain_leak_review |
dynamic_review_required |
cookie_conflicting_writes_review |
dynamic_review_required |
jwt_alg_none_accepted |
high_confidence_misconfiguration for literal none; framework_default_assumed for default-sensitive library behavior |
jwt_alg_confusion_signal |
high_confidence_misconfiguration for deterministic mixed algorithm families; dynamic_review_required for key-family ambiguity |
jwt_jku_header_trust |
dynamic_review_required |
jwt_x5u_header_trust |
dynamic_review_required |
jwt_embedded_jwk_trust |
dynamic_review_required |
jwt_nbf_missing |
missing_validation_evidence |
jwt_clock_skew_review |
dynamic_review_required |
jwt_kid_unvalidated_review |
missing_validation_evidence |
oauth_pkce_missing_review |
dynamic_review_required |
oauth_state_missing |
missing_validation_evidence |
oauth_state_static_review |
dynamic_review_required |
oauth_state_unverified_review |
missing_validation_evidence |
oidc_nonce_missing |
missing_validation_evidence |
oidc_nonce_unverified_review |
missing_validation_evidence |
oauth_redirect_uri_wildcard_review |
dynamic_review_required |
token_in_local_storage |
high_confidence_misconfiguration |
token_in_session_storage |
high_confidence_misconfiguration |
token_in_url_path_or_fragment |
high_confidence_misconfiguration |
client_secret_in_browser_code |
dynamic_review_required |
jwt_denylist_absent_on_logout_review |
lifecycle_gap |
refresh_family_revocation_absent_on_logout_review |
lifecycle_gap |
sliding_expiry_without_rotation_review |
lifecycle_gap |
password_change_global_revocation_absent_review |
lifecycle_gap |
Rules:
- Prefer existing category semantics over adding near-duplicate category names.
- Keep cryptographic trust evidence in the category that describes the static certainty: deterministic unsafe configuration, missing validation evidence, or dynamic review.
- Keep SARIF stable by mapping findings through the existing category rule IDs.
- Revisit a dedicated cryptographic-trust category only if future checks cannot be accurately expressed as deterministic misconfiguration, missing validation, lifecycle gap, dynamic review, or framework default evidence.