Skip to content

fix(auth): normalize bearer-token comparison to fixed-size digests - #790

Draft
seonghobae wants to merge 6 commits into
developfrom
sentinel-hmac-timing-leak-454043180780305011
Draft

fix(auth): normalize bearer-token comparison to fixed-size digests#790
seonghobae wants to merge 6 commits into
developfrom
sentinel-hmac-timing-leak-454043180780305011

Conversation

@seonghobae

@seonghobae seonghobae commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

Security boundary

Python documents that hmac.compare_digest() avoids content-based short-circuiting but can theoretically reveal operand type or length when the inputs have different lengths. The first version of this branch checked raw credential length and then called compare_digest(credentials, credentials) on the mismatch path. That self-comparison does not normalize the secret-dependent comparison boundary and a 401 response does not prove wall-clock equality.

The repaired boundary keeps the existing 4 KiB Authorization-header admission limit, precomputes the configured token's SHA-256 digest once when immutable RuntimeSettings is created, hashes each bounded presented credential to the same 32-byte size, and invokes hmac.compare_digest() once on equal-length digests.

RED → GREEN

  • RED faedf8d9103f8a510b35b49570124071cc875a36: require a precomputed fixed-size configured-token digest, equal-size operands at compare_digest() for a mismatched credential, and preservation of exact-token authentication semantics.
  • GREEN 1d4e61de2a879561cfeeb7871c1d01cc37114fad: precompute the configured token digest outside the request path after normalization and length validation.
  • GREEN 139c8440b894690a2f0d6dea2d183409bbf5361f: hash the bounded presented credential and compare the two fixed-size digests exactly once.
  • Documentation repair e35b37e858b8fafd272d1428b5bceb97e16ae45c: replace the inaccurate self-comparison/constant-time claim with the actual Python contract and implementation boundary.
  • Baseline 97e821d7575014de6580ed6e43307e8ede0799d1: record the current authentication contract, evidence, acceptance boundary, official Python traceability, and the remaining Keyverse identity-integration decision in docs/product-technical-gap-baseline.md.

Exact current authority

  • target: develop@e06b1f3fb10903569124af011da213951e6e2473
  • exact head: 97e821d7575014de6580ed6e43307e8ede0799d1
  • state: Draft

Predecessor checks/reviews do not transfer after these commits. Keep Draft until this unchanged exact head has terminal tests, lint/type/quality and repository security checks plus current review/thread evidence. Do not add source-neutral retrigger commits, restore raw unequal-length comparison, claim a 401 latency test proves constant-time HTTP behavior, suppress findings, or weaken required gates.

Primary reference

Python Software Foundation. (2026). hmac — Keyed-hashing for message authentication. Python 3.14.7 documentation. Retrieved September 3, 2026, from https://docs.python.org/3/library/hmac.html

@google-labs-jules

Copy link
Copy Markdown

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@coderabbitai

coderabbitai Bot commented Sep 2, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Approval pending

CodeRabbit has no unresolved comments, but it has not reviewed the latest commit.

Use the checkbox below to review the latest commit. CodeRabbit will approve the changes if it finds no blocking issues.

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Bearer 토큰 검증이 토큰 길이를 먼저 비교하도록 변경되었습니다. 길이가 다르면 더미 hmac.compare_digest 호출 후 401 응답을 반환합니다. 관련 테스트와 보안 문서가 추가되었습니다.

Changes

Bearer 토큰 인증

Layer / File(s) Summary
토큰 비교 및 검증
src/newsdom_api/main.py, tests/test_auth.py, .jules/sentinel.md
토큰 길이가 다르면 더미 hmac.compare_digest 호출 후 unauthorized 응답을 반환합니다. 길이가 같을 때만 실제 토큰을 비교합니다. 다른 길이의 토큰이 401 응답을 받는 테스트와 관련 보안 문서를 추가했습니다.

Estimated code review effort: 2 (Simple) | ~10 minutes

Merge Risk: 🔵 Low · up to 6d2c6

Authentication continues to reject invalid credentials with 401 responses, but the unequal-length comparison path may still expose token-length timing information, so the security hardening needs explicit owner follow-up before or alongside merge.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning 설명은 보안 변경과 구현 경계를 상세히 설명하지만 템플릿의 ## Summary, ## Git Flow target, ## Verification, ## Notes 섹션을 따르지 않습니다. 테스트 검증 체크리스트와 Git Flow 대상 브랜치도 명시하지 않았습니다. 템플릿에 맞춰 ## Summary, ## Git Flow target, ## Verification, ## Notes 섹션을 추가하십시오. 대상 브랜치를 명시하고 pytestPYTHONWARNINGS=error pytest 실행 결과를 체크하십시오. 릴리스 또는 hotfix 후속 작업이 없으면 ## Notes에 없다고 명시하십시오.
✅ Passed checks (4 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 3 functions across 2 files. (1 skipped: 1 …
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed 제목은 고정 크기 digest를 사용한 bearer-token 비교 정규화라는 주요 변경을 정확하고 간결하게 설명합니다.
Full details: Docstring Coverage

Explanation

Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 3 functions across 2 files. (1 skipped: 1 unsupported.)

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch sentinel-hmac-timing-leak-454043180780305011

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

devin-ai-integration[bot]

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as resolved.

@seonghobae
seonghobae marked this pull request as draft September 2, 2026 22:46
@seonghobae seonghobae changed the title 🛡️ Sentinel: [MEDIUM] hmac.compare_digest 토큰 길이 차이로 인한 정보 유출 방지 fix(auth): normalize bearer-token comparison to fixed-size digests Sep 2, 2026

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Devin Review found 2 new potential issues.

Devin Review

Comment thread src/newsdom_api/config.py

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔍 필수 품질 게이트 미검증

현재 환경에 uvpytest가 없어 전체 테스트와 100% 분기 커버리지를 실행하지 못했다. CI 결과를 확인해야 한다.

Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment thread tests/test_auth.py
Comment on lines +411 to +422
def test_authentication_constant_time_comparison_differing_lengths():
'''Verify that tokens of different lengths do not leak length information.'''
settings = RuntimeSettings(api_token="valid_token")
app = create_app(settings)
client = TestClient(app)

response = client.post(
"/parse",
headers={"Authorization": "Bearer too_short"},
files={"file": ("test.pdf", b"%PDF-1.4\n", "application/pdf")},
)
assert response.status_code == 401

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔍 추가 테스트의 형식 불일치

test_authentication_constant_time_comparison_differing_lengths는 반환 형식 주석과 테스트 간 빈 줄이 없다. 저장소의 일관된 테스트 형식에 맞춰 정리해야 한다.

Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.


from fastapi.testclient import TestClient

import newsdom_api.main as main_module
Comment thread src/newsdom_api/config.py
"The configured parser authentication token is too long"
)
object.__setattr__(self, "api_token", normalized_token)
object.__setattr__(self, "api_token_digest", hashlib.sha256(token_bytes).digest())
@seonghobae seonghobae added bug Something isn't working priority: medium Normal-priority or P2 work type: bug Defect or incorrect behavior labels Sep 7, 2026 — with ChatGPT Codex Connector
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working priority: medium Normal-priority or P2 work type: bug Defect or incorrect behavior

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants