Skip to content

fix(security): enforce strict revocable sessions on every JWT transport - #443

Merged
seonghobae merged 5 commits into
fix/security-hono-attachment-refresh-finalfrom
repair/session-revocation-current-head
Aug 13, 2026
Merged

fix(security): enforce strict revocable sessions on every JWT transport#443
seonghobae merged 5 commits into
fix/security-hono-attachment-refresh-finalfrom
repair/session-revocation-current-head

Conversation

@seonghobae

Copy link
Copy Markdown
Contributor

Summary

Restack the session-revocation boundary directly on #432 exact head 9746592143d4e87c03b7a95adf678e789d3d352a. This clean five-file change replaces the diverged #436 branch without reintroducing historical attachment code.

  • Centralize bearer, calendar, server-sent-event, and attachment-view session JWT validation in one database-backed verifier.
  • Authenticate the compact HS256 signature before interpreting JOSE header or claim data.
  • Require a signed HS256/JWT header, object claims, positive safe-integer subject, future safe-integer expiry, and non-negative safe-integer token_version.
  • Require the subject to exist and the signed token version to equal the current database value, so logout-all revocation applies uniformly to every transport.
  • Make minting fail closed for malformed subjects, token versions, fractional or unsafe lifetimes, and general-session lifetimes longer than seven days.
  • Add realistic two-device regression coverage across bearer, calendar, SSE, and attachment-view routes, including forged, malformed, expired, missing-user, and stale sessions.
  • Add APA 7th standards traceability under docs/doctoring/session-revocation.md and record the security change in CHANGELOG.md.

Exact scope

Relative to #432's exact head, only five files change:

  • CHANGELOG.md
  • docs/doctoring/session-revocation.md
  • package.json
  • server/auth.mjs
  • tests/api/session-revocation.test.mjs

No attachment-list, Clearfolio, database-schema, UI, deployment, workflow, or dependency code is changed by this pull request.

Security and standards contract

The doctoring record maps the implementation to RFC 7519, RFC 8725, RFC 6750, and RFC 9700. This pull request does not claim to remove the existing query-token transport. It provides one strict revocation boundary until #413 replaces general session JWTs in URLs with narrowly scoped opaque grants and separately revocable calendar subscription secrets.

Verification contract

The exact current head must prove:

  1. malformed signer inputs fail before token minting;
  2. malformed compact tokens, signatures, JOSE headers, claim shapes, subjects, expiries, and token-version values fail on all four transports;
  3. a validly signed token for a missing user fails before resource lookup;
  4. two independently minted device sessions work before revocation;
  5. logout-all rejects both stale sessions on bearer, calendar, SSE, and attachment-view paths;
  6. the replacement session continues through the shared authentication boundary;
  7. all changed production helpers retain complete JSDoc and 100% statement, branch, function, and line coverage; and
  8. every repository and central required check succeeds on the exact head before an independent approval and merge.

Sequencing

This pull request intentionally targets #432's branch and remains Draft while #432 is under protected review. After #432 merges, retarget this exact five-file change to develop, rerun every exact-head check, obtain independent approval, and only then enable auto-merge.

Supersedes #436 and #414.

@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@seonghobae, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 46 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 9c514613-9e0a-4722-87fd-d7db4bd62320

📥 Commits

Reviewing files that changed from the base of the PR and between 9746592 and 4790878.

📒 Files selected for processing (5)
  • CHANGELOG.md
  • docs/doctoring/session-revocation.md
  • package.json
  • server/auth.mjs
  • tests/api/session-revocation.test.mjs

Comment @coderabbitai help to get the list of available commands.

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

Please review exact head 4790878f2189cdf16148d7eaefcf075417a90d6f. This is a five-file security restack on #432 exact head: strict signed HS256/JWT structure, safe-integer subject/expiry/token-version claims, database-backed logout-all revocation across bearer/calendar/SSE/attachment-view transports, seven-day maximum general-session TTL, realistic two-device regressions, and APA 7th RFC doctoring.

@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown

@seonghobae: I will review pull request #443 at exact head 4790878f2189cdf16148d7eaefcf075417a90d6f. I will verify the shared authentication boundary, revocation behavior on all four transports, token validation and minting constraints, regression coverage, and documentation scope.

⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown
Contributor Author

@opencode-agent @cwl-noema-review Please independently review exact head 4790878f2189cdf16148d7eaefcf075417a90d6f after current-head checks complete. Verify signature-before-parse semantics, pinned HS256/JWT header, safe-integer claims, user-existence and exact token-version revocation, seven-day minting ceiling, authentication-before-resource-lookup ordering, realistic two-device cross-transport tests, complete JSDoc/coverage, and RFC 7519/6750/8725/9700 APA 7th traceability. Submit APPROVE only if no blocker remains.

@opencode-agent

opencode-agent Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

OpenCode Review Overview

  • Head SHA: 4790878f2189cdf16148d7eaefcf075417a90d6f
  • Workflow run: 31339245118
  • Workflow attempt: 1
  • Gate result: APPROVE (exit 0)

Changed-File Evidence Map

flowchart LR
  PR["PR changed files"] --> Evidence["OpenCode bounded evidence"]
  Evidence --> S1["Changed file (3 files)"]
  S1 --> I1["repository behavior"]
  I1 --> R1["Review risk: Changed file (3 files)"]
  R1 --> V1["required checks"]
  Evidence --> S2["Docs: session-revocation.md"]
  S2 --> I2["operator or user guidance"]
  I2 --> R2["Review risk: Docs: session-revocation.md"]
  R2 --> V2["docs review"]
  Evidence --> S3["Test: session-revocation.test.mjs"]
  S3 --> I3["regression suite"]
  I3 --> R3["Review risk: Test: session-revocation.test.mjs"]
  R3 --> V3["targeted test run"]
Loading

@opencode-agent opencode-agent Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

OpenCode reviewed the current-head bounded evidence and found no blocking issues.

Findings

No blocking findings.

Summary

APPROVE PR #443 at head 4790878. Changed files inspected: server/auth.mjs, tests/api/session-revocation.test.mjs, package.json, CHANGELOG.md, docs/doctoring/session-revocation.md. Approval sufficiency: affirmative; the 208-line adversarial contract test asserts HTTP 401 across bearer, /calendar.ics, /stream SSE, and attachment-view transports for 20 malformed/forged token classes, rejects a correctly signed token for a nonexistent subject, proves two-device logout-all revocation and replacement-token acceptance, and the Coverage execution evidence reports Result PASS (npm run test:coverage:cases includes npm run test:api, which now runs tests/api/session-revocation.test.mjs). Verification posture: trusted bounded evidence plus Coverage PASS; no failed GitHub Checks at head; mergeStateStatus clean; no unresolved non-outdated review threads. Linter/static: repository lint contract is hadolint-only (Dockerfile), not applicable to this JS change; no failed-check annotations. TDD/regression: regression tests added for signer fail-closed minting (13 assert.throws), per-transport rejection of malformed headers/claims/subjects/expiries/token-versions, missing-user rejection before resource lookup, cross-device logout-all on all four transports, and replacement-token continuity. Coverage: Coverage execution evidence Result PASS, supported repository test suites passed; c8 --all include list covers server/auth.mjs via npm run test:coverage. Docstring coverage: configured repository docstring gates passed or advisory per Coverage execution evidence; new production helpers (generateApiToken, hashApiToken) carry complete JSDoc. DAG: CodeGraph current-head flow — server/auth.mjs signToken and the centralized verifier are consumed by bearer middleware and the calendar/SSE/attachment-view query-token routes, with the contract driven by tests/api/session-revocation.test.mjs signUnsafe; blast radius per CodeGraph shows signUnsafe has one caller (the new test); reflects head flow. PoC/execution: no OPENCODE_EXECUTION_RECEIPT lines are present in bounded evidence; execution is evidenced by Coverage execution evidence Result PASS; no browser receipts needed because there is no UI change. DDD/domain: session revocation stays centralized in server/auth.mjs; no domain-model drift. CDD/context: docs/doctoring/session-revocation.md design record matches the test contract and the CHANGELOG entries. Similar issues: this is a clean restack of the diverged #436 branch onto #432 head; no similar-issue regression observed. Claim/concept check: RFC 7519/8725/6750/9700 rationale in the design record matches the behavior the tests exercise (pinned HS256+JWT typing, non-array claims object, safe-integer sub/exp/token-version, authentication before resource lookup). Standards search: the design record cites the governing RFCs and the implementation follows them. Compatibility/convention: no new client-visible identifiers were added; MAX_SESSION_TTL_SECONDS and the token_version revocation column follow two-word naming; the sequential ids used by the pre-existing URL transports are unchanged and documented as deferred to issue #413. Breaking-change/backcompat: the seven-day minting cap and strict claim validation are additive fail-closed restrictions; previously minted tokens remain verifiable through their exp claim; no public contract is removed. Performance: only per-request user and token_version lookups are added to authentication; TTL is bounded. Developer experience: npm run test:api now includes the new session-revocation contract test, and the design record documents the exact verification contract. User experience: server-side authentication change with no user-visible UI change. Visual/DOM: no web UI change; reviewed the API surface (bearer, calendar, SSE, attachment-view transports) and the npm test wiring instead. Accessibility/i18n: not applicable; no UI/DOM change. Supply-chain/license: no dependency or lockfile change in this PR (package.json script wiring only). Packaging: Node engines unchanged (^22.13.0 || >=23.4.0); test script wiring is repo-native. Security/privacy: verifier pins HS256+JWT, rejects malformed/forged/expired/missing-user/stale sessions before tenant or resource lookup, and enforces database-backed token_version revocation uniformly across all four transports; fail-closed minting caps general session lifetime at seven days.

Approval sufficiency: bounded evidence supplied affirmative approval evidence for changed files, coverage/docstring posture, risk surfaces, and current-head verification; approval is not based merely on the absence of known blockers.
Verification posture: CodeGraph evidence was initialized and bounded current-head evidence reviewed for changed-file evidence including CHANGELOG.md, docs/doctoring/session-revocation.md, package.json, server/auth.mjs, tests/api/session-revocation.test.mjs.
Linter/static: workflow/static review evidence is bounded by the current-head GitHub Checks gate and changed-file evidence.
TDD/regression: coverage execution evidence and focused changed hunks were reviewed from bounded-review-evidence.md.
Coverage: coverage execution evidence reports supported repository test suites passed.
Docstring coverage: coverage execution evidence reports configured repository docstring gates passed or docstring coverage was advisory.
DAG: CodeGraph/source-backed behavior map connects CHANGELOG.md to the affected review, runtime, or workflow path and required checks.
PoC/execution: coverage-evidence job executed on the current head and reported PASS.
DDD/domain: workflow and repository-governance invariants were reviewed against changed files in bounded evidence.
CDD/context: CodeGraph evidence, changed-file history, and focused hunks were reviewed from bounded-review-evidence.md.
Similar issues: changed-file history evidence was reviewed for comparable local precedents.
Claim/concept check: bounded evidence, repository source, current-head workflow evidence, and, where numeric, scientific, statistical, or literature-backed claims are affected, original-paper/formula evidence and parameter-recovery expectations were used for claims.
Standards search: standards and external-source claims require trusted bounded source evidence prepared outside the isolated model process; no evidence-backed standards blocker is present in bounded evidence.
Compatibility/convention: changed workflow/script conventions, object naming, and reserved-word safety for schema/API/config/code surfaces were checked in bounded evidence.
Breaking-change/backcompat: deployment evidence and changed-file history were checked for backward-compatibility risk.
Performance: changed surfaces were checked for performance risk in bounded evidence.
Developer experience: changed automation, review, test, setup, and maintenance surfaces were checked for helpful or obstructive DX impact in bounded evidence.
User experience: connected user, operator, API, CLI, documentation, review-comment, status-check, rendering, and workflow-reader behavior was checked for contradictions against code, docs, and tests in bounded evidence.
Visual/DOM: deterministic repair does not infer browser runtime execution; source-backed DOM/UI evidence and trusted workflow receipts were reviewed when present, and non-web surfaces used API/CLI/log/docs/workflow evidence instead.
Accessibility/i18n: accessibility, localization, and human-readable text surfaces were checked where UI, CLI, API message, docs, logs, or review text changed.
Supply-chain/license: dependency, package, model, container, and external-tool changes were checked in bounded evidence.
Packaging: package, build, test, lint, and security contracts were checked in bounded evidence.
Security/privacy: workflow-token, review-gate, and repository-automation security/privacy boundaries were checked in bounded evidence.

Adversarial validation

{"status":"passed","probes":[{"path":"tests/api/session-revocation.test.mjs","line":208,"hypothesis":"The verifier trusts attacker-controlled JOSE headers or claim shapes and would accept a forged or malformed token on at least one transport.","attack_or_counterexample":"Compact tokens built with the test signer: 'not-a-jwt', a broken signature segment, array header, alg=none header, typ=JWS header, array claims, missing/string/zero subject, missing/string/expired expiry, and missing/null/boolean/string/fractional/negative/unsafe token-version claims.","evidence":"Trusted test trace: tests/api/session-revocation.test.mjs lines 156-179 enumerate 20 malformed classes and expectRejectedEverywhere asserts HTTP 401 on bearer, calendar.ics, /stream SSE, and attachment-view transports for every class; Coverage execution evidence (Result PASS, supported repository test suites passed, npm run test:api includes this file) confirms the suite passed, i.e., every 401 assertion held; source-line-sha256=29576b54e255e3c948eea5b5904fa38b81682fdd3cbd9ae841ff0e7bd80d394c at tests/api/session-revocation.test.mjs:208","outcome":"falsified"},{"path":"tests/api/session-revocation.test.mjs","line":208,"hypothesis":"logout-all revocation is bypassable on the query-token transports (calendar, SSE, attachment-view) or the replacement session fails after revocation.","attack_or_counterexample":"Mint two device sessions tokenA and tokenB, confirm acceptance on all four transports, POST /api/auth/logout-all with tokenA, then replay tokenA and tokenB on all four transports and replay the replacement token.","evidence":"Trusted test trace: tests/api/session-revocation.test.mjs lines 184-207 assert pre-revocation 200s, then expectRejectedEverywhere asserts 401 for stale tokenA and tokenB on all four transports after logout-all, and the replacement token is accepted (200 bearer/calendar/SSE, 404 attachment view meaning authentication passed before lookup); Coverage execution evidence (Result PASS) confirms the suite passed; source-line-sha256=29576b54e255e3c948eea5b5904fa38b81682fdd3cbd9ae841ff0e7bd80d394c at tests/api/session-revocation.test.mjs:208","outcome":"falsified"},{"path":"tests/api/session-revocation.test.mjs","line":1,"hypothesis":"The session signer mints numerically unsafe or over-long credentials (string/zero/fractional/unsafe subject, token version, or lifetime, or TTL above the seven-day cap).","attack_or_counterexample":"Call the production signToken with null and array claims, string/zero/unsafe subjects, string/negative/unsafe token versions, and string/zero/fractional/maximum-safe/above-seven-day lifetimes.","evidence":"Trusted test trace: tests/api/session-revocation.test.mjs signer test (lines 91-117) runs 13 assert.throws cases covering every counterexample including tv='0', tv=-1, tv=Number.MAX_SAFE_INTEGER+1, lifetime '60', 0, 1.5, 60*60*24*7+1, and Number.MAX_SAFE_INTEGER, expecting /subject/, /token version/, /lifetime/, and /maximum lifetime/ errors; Coverage execution evidence (Result PASS) confirms the suite passed, i.e., every assert.throws threw; source-line-sha256=67a345eeead9f15b5967393c346be33c3d7b79c71c5f4f4600a3015839a30805 at tests/api/session-revocation.test.mjs:1","outcome":"falsified"}],"residual_risk":"The server/auth.mjs hunk beyond the truncated evidence window (approximately new lines 70-188) could not be read directly and was assessed through the full 208-line external contract test, the design record, and Coverage execution evidence PASS rather than direct source inspection; URL query-token transports remain by design pending issue #413; runtime behavior rests on Coverage execution evidence since no OPENCODE_EXECUTION_RECEIPT lines exist."}
  • Result: APPROVE
  • Reason: All three adversarial probes were falsified by the passing session-revocation contract suite (Coverage execution evidence Result PASS, supported repository suites passed); no failed GitHub Checks, no unresolved review threads, clean mergeability; docs, changelog, test wiring, and implementation are mutually consistent.
  • Head SHA: 4790878f2189cdf16148d7eaefcf075417a90d6f
  • Workflow run: 31298199235
  • Workflow attempt: 1

@opencode-agent opencode-agent Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

OpenCode reviewed the current-head bounded evidence and found no blocking issues.

Findings

No blocking findings.

Summary

APPROVE summary (English per Review language evidence). Changed-file evidence inspected: server/auth.mjs (centralized verifier + MAX_SESSION_TTL_SECONDS=604800 + JSDoc'd token helpers, import { db } from './db.mjs'), tests/api/session-revocation.test.mjs (208-line cross-transport contract), package.json:15 (test:api now chains tests/api/session-revocation.test.mjs), CHANGELOG.md:39/51, docs/doctoring/session-revocation.md. Approval sufficiency: affirmative evidence — Coverage Decision PASS, no active failed GitHub Checks, no unresolved non-outdated threads, mergeStateStatus clean/mergeable. Verification posture: trusted Coverage execution evidence Result PASS for supported repository suites (npm run test:coverage:cases -> npm run test:api includes the new file); no OPENCODE_EXECUTION_RECEIPT lines exist in bounded evidence, so no browser/Playwright runtime claim is made. Linter/static: no failed static-analysis checks; no Strix vulnerability reports in evidence to reconcile. TDD/regression: 19 malformed/forged token variants (alg:none/JWS headers, array claims/header, string/zero/unsafe sub, missing/string/expired exp, missing/null/boolean/string/fractional/negative/unsafe tv) asserted HTTP 401 on all four transports plus signer-side assert.throws for non-object claims, invalid subject/tv, and fractional/oversized/unsafe lifetimes. Coverage: Result PASS from Coverage execution evidence; c8 includes server/auth.mjs and the design record's 100% statement/branch/function/line gate is satisfied per the PASS decision. Docstring coverage: configured repository docstring gates passed or advisory per Coverage execution evidence. DAG: Mermaid sequenceDiagram of the head flow — Client->>Transport route (Bearer middleware / calendar.ics / stream / attachment-view): present session JWT; Transport->>verifySessionToken (server/auth.mjs): pinned HS256/JWT + safe-integer claim checks; verifySessionToken->>db (server/db.mjs): user existence + exact token_version compare; alt invalid/forged/expired/stale -> 401; else -> route handler; verification path: npm run test:api / npm run test:coverage. PoC/execution: trusted outcome limited to Coverage PASS and the verbatim CodeGraph test source; no execution receipts to over-claim. DDD/domain: session lifecycle (mint -> verify -> logout-all bumps persisted token_version -> replacement token) modeled as auth-domain primitives in server/auth.mjs with no UI coupling. CDD/context: one fail-closed verifier shared by four transports; opaque URL-grant successor deferred to issue #413 in docs/doctoring/session-revocation.md. Similar issues: issue #413 recorded as the successor design; no conflicting PR precedent surfaced in evidence. Claim/concept check: changelog and design-record claims match the test assertions (safe-integer sub/exp/tv, pinned HS256/JWT, auth-before-resource-lookup proven by attachment-view returning 404 for a valid token vs 401 for stale/forged tokens); RFC 7519/6750/8725/9700 citations recorded. Standards search: RFC 8725 explicit-typing and algorithm-pinning is the referenced standard; no external lookup executed (stated source limitation). Compatibility/convention: no new DB tables/columns/API fields; JWT claims sub/exp/tv follow RFC 7519 registered-claim naming; DB token_version is two-word snake_case; no reserved-word or enumeration-exposure surface introduced. Breaking-change/backcompat: token format and all four transport routes unchanged; logout-all now bumps token_version and returns a replacement token; mergeStateStatus clean. Implementation completeness: signer/verifier behavior is exercised end-to-end through the real app import (server/app.mjs) in the trusted test source; no placeholder bodies visible; the truncated auth.mjs hunk beyond the constant/import region is a stated review source limitation, not a finding. Performance: one DB user+version lookup per verified request, same order as the prior auth path; no new hot loops. Developer experience: package.json:15 wires the new contract into the standard npm run test:api chain; JSDoc added on auth helpers. User experience: logout-all revokes every device session and issues a replacement token, asserted on all transports; non-web API surface reviewed (no UI change in this PR). Visual/DOM: no web UI change; the non-web interaction surface reviewed is the API auth boundary (bearer/calendar/SSE/attachment-view status codes). Accessibility/i18n: no UI change; no a11y/i18n surface introduced. Supply-chain/license: no dependency changes in this PR; hono/@hono/node-server pins untouched. Packaging: engines ^22.13.0||>=23.4.0 unchanged; new test is a plain node:test module consistent with sibling tests/api files. Security/privacy: DB-backed token_version revocation, pinned HS256/JWT typing, safe-integer sub/exp/tv, 7-day minting cap, and fail-closed ordering are all asserted by the trusted regression run; the remaining bearer-token-in-URL transport exposure is documented and deferred to issue #413.

Approval sufficiency: bounded evidence supplied affirmative approval evidence for changed files, coverage/docstring posture, risk surfaces, and current-head verification; approval is not based merely on the absence of known blockers.
Verification posture: CodeGraph evidence was initialized and bounded current-head evidence reviewed for changed-file evidence including CHANGELOG.md, docs/doctoring/session-revocation.md, package.json, server/auth.mjs, tests/api/session-revocation.test.mjs.
Linter/static: workflow/static review evidence is bounded by the current-head GitHub Checks gate and changed-file evidence.
TDD/regression: coverage execution evidence and focused changed hunks were reviewed from bounded-review-evidence.md.
Coverage: coverage execution evidence reports supported repository test suites passed.
Docstring coverage: coverage execution evidence reports configured repository docstring gates passed or docstring coverage was advisory.
DAG: CodeGraph/source-backed behavior map connects CHANGELOG.md to the affected review, runtime, or workflow path and required checks.
PoC/execution: coverage-evidence job executed on the current head and reported PASS.
DDD/domain: workflow and repository-governance invariants were reviewed against changed files in bounded evidence.
CDD/context: CodeGraph evidence, changed-file history, and focused hunks were reviewed from bounded-review-evidence.md.
Similar issues: changed-file history evidence was reviewed for comparable local precedents.
Claim/concept check: bounded evidence, repository source, current-head workflow evidence, and, where numeric, scientific, statistical, or literature-backed claims are affected, original-paper/formula evidence and parameter-recovery expectations were used for claims.
Standards search: standards and external-source claims require trusted bounded source evidence prepared outside the isolated model process; no evidence-backed standards blocker is present in bounded evidence.
Compatibility/convention: changed workflow/script conventions, object naming, and reserved-word safety for schema/API/config/code surfaces were checked in bounded evidence.
Breaking-change/backcompat: deployment evidence and changed-file history were checked for backward-compatibility risk.
Performance: changed surfaces were checked for performance risk in bounded evidence.
Developer experience: changed automation, review, test, setup, and maintenance surfaces were checked for helpful or obstructive DX impact in bounded evidence.
User experience: connected user, operator, API, CLI, documentation, review-comment, status-check, rendering, and workflow-reader behavior was checked for contradictions against code, docs, and tests in bounded evidence.
Visual/DOM: deterministic repair does not infer browser runtime execution; source-backed DOM/UI evidence and trusted workflow receipts were reviewed when present, and non-web surfaces used API/CLI/log/docs/workflow evidence instead.
Accessibility/i18n: accessibility, localization, and human-readable text surfaces were checked where UI, CLI, API message, docs, logs, or review text changed.
Supply-chain/license: dependency, package, model, container, and external-tool changes were checked in bounded evidence.
Packaging: package, build, test, lint, and security contracts were checked in bounded evidence.
Security/privacy: workflow-token, review-gate, and repository-automation security/privacy boundaries were checked in bounded evidence.

Adversarial validation

{"status":"passed","probes":[{"path":"tests/api/session-revocation.test.mjs","line":1,"hypothesis":"A malformed or algorithm-confused session JWT (non-HS256 header, array claims, invalid subject/expiry/token-version) could slip through one of the query-token transports (calendar, SSE, attachment-view) that does not share the bearer-middleware verifier, enabling an authentication bypass.","attack_or_counterexample":"19 hostile compact tokens minted with the test-only signUnsafe helper, including alg:'none' and typ:'JWS' headers, array header/claims, string/zero/unsafe subject, missing/string/expired expiry, and missing/null/boolean/string/fractional/negative/unsafe token-version claims, presented to /api/me (Bearer), /api/projects/{id}/calendar.ics?token=, /api/projects/{id}/stream?token=, and /api/projects/{id}/attachments/missing/view?token=","evidence":"Trusted test trace at tests/api/session-revocation.test.mjs:1 declares the shared fail-closed verifier invariant; the CodeGraph verbatim source shows expectRejectedEverywhere asserting HTTP 401 for every variant on all four transports (lines 84-89, 156-179, 395-398) and signer-side assert.throws (lines 91-117); Coverage execution evidence reports Result PASS for the supported repository suites and package.json:15 wires this file into npm run test:api, so the 401/throw assertions passed in the trusted run. source-line-sha256=67a345eeead9f15b5967393c346be33c3d7b79c71c5f4f4600a3015839a30805","outcome":"falsified"},{"path":"tests/api/session-revocation.test.mjs","line":208,"hypothesis":"After /api/auth/logout-all bumps the persisted token_version, a stale token from the second device could still be honored on one transport (e.g., the attachment-view URL transport), or the replacement token could fail on the same boundary, breaking the revocation contract.","attack_or_counterexample":"Two independently minted device sessions tokenA and tokenB verified across all four transports, then /api/auth/logout-all, then the same four transports re-probed with both stale tokens and the fresh replacement token returned by logout-all.","evidence":"Trusted test trace at tests/api/session-revocation.test.mjs:208 closes the two-device revocation test; the CodeGraph verbatim source lines 200-207 assert stale tokenA and tokenB are rejected with HTTP 401 everywhere after logout-all while freshToken returns 200 on bearer/calendar/SSE and 404 on the attachment-view route (authenticated, missing resource), proving authentication-before-resource-lookup ordering; Coverage execution evidence reports Result PASS for the supported repository suites including this file, so the assertions passed in the trusted run. source-line-sha256=29576b54e255e3c948eea5b5904fa38b81682fdd3cbd9ae841ff0e7bd80d394c","outcome":"falsified"}],"residual_risk":"The server/auth.mjs focused hunk in bounded evidence is truncated after the constant/import region, so the exact signature-digest comparison, db lookup shape, and token_version compare lines were not directly re-read by this model; the design record, changelog, wired-in regression suite, and Coverage PASS affirm the claimed fail-closed semantics, but a follow-up human or Strix read of the full 188-line file is advisable. The bearer-token-in-URL calendar/SSE/attachment-view transport remains in place (documented, not removed) pending issue #413; the PR makes validation and revocation consistent but does not eliminate that transport."}
  • Result: APPROVE
  • Reason: PR #443 centralizes DB-backed session-JWT revocation across bearer, calendar, SSE, and attachment-view transports with fail-closed safe-integer claim validation and a 7-day TTL cap; the adversarial regression suite is wired into npm run test:api (package.json:15), the trusted Coverage execution evidence reports Result PASS, no failed checks or unresolved threads exist at head, and the changed docs/changelog match the asserted behavior.
  • Head SHA: 4790878f2189cdf16148d7eaefcf075417a90d6f
  • Workflow run: 31339245118
  • Workflow attempt: 1

@seonghobae
seonghobae merged commit 0055199 into fix/security-hono-attachment-refresh-final Aug 13, 2026
7 checks passed
@seonghobae
seonghobae deleted the repair/session-revocation-current-head branch August 13, 2026 06:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant