Skip to content

fix(api): enforce canonical hex format on validate_key_format (#2427) - #2491

Merged
endxxxx merged 1 commit into
MemTensor:dev-v2.0.36from
RerankerGuo:fix/issue-2427-canonical-hex
Oct 29, 2026
Merged

endxxxx merged 1 commit into
MemTensor:dev-v2.0.36from
RerankerGuo:fix/issue-2427-canonical-hex

Conversation

@RerankerGuo

Copy link
Copy Markdown
Contributor

Summary

validate_key_format exists as a separate copy in two modules. Both used int(hex_part, 16) to verify the 64-char hex tail, which silently passes for leading signs, 0x prefixes, _ separators, and surrounding whitespace — so the documented format krlk_<64-lowercase-hex> was not actually enforced at the middleware boundary.

Root cause

Two copies of the same buggy validator:

  • src/memos/api/utils/api_keys.py:48 — used by the key-creation utilities
  • src/memos/api/middleware/auth.py:65 — gates every authenticated request

Both check the tail via int(hex_part, 16). CPython accepts:

input int(..., 16) result
+aaaa… (64 chars) valid
0xaaaa… (62 chars) valid
aaaa_bbbb… (with _) valid (PEP 515)
AAAA… / AAAA… valid

So krlk_+a..a, krlk_0x.., krlk_a_a, krlk_A..A, etc. were all accepted by the middleware, hashed verbatim, and looked up against the database — bypassing the canonical form that generate_api_key() produces (lowercase, no prefixes, no separators, no signs, no whitespace).

Fix

Two changes that together eliminate the bug class:

  1. Canonical validator — src/memos/api/utils/api_keys.py: replace the int(hex_part, 16) check with an anchored regex re.fullmatch(r"[0-9a-f]{64}", hex_part). Only the exact 64-lowercase-hex form is valid.
  2. Dedup — src/memos/api/middleware/auth.py: import the canonical implementation under the name validate_key_format_canonical, keep the public symbol validate_key_format as a one-line re-export. This prevents the two copies from drifting again (the original bug class).

Tests

New tests/api/test_validate_key_format.py, 21 cases:

  • canonical format and generate_api_key() output (20 random samples) always pass
  • 15 non-canonical variants are rejected: signs, 0x prefix, underscore separators, uppercase hex, leading/trailing whitespace, wrong length, missing krlk_ prefix, Bearer prefix, empty string
  • both utils and middleware copies enforce the same contract

Verification

PYTHONPATH=src pytest tests/api/test_validate_key_format.py -v
============================== 21 passed in 3.31s ==============================

Ruff: ruff format --check and ruff check both clean on touched files (0 new findings vs main; the 3 pre-existing DTZ/datetime.utcnow warnings in api_keys.py are out of scope).

Out of scope

  • No new dependencies
  • No public API / OpenAPI contract changes
  • No DB schema, migration, or graph model changes
  • No Makefile / pyproject.toml / pre-commit / GitHub workflow changes

Closes #2427

@Memtensor-AI Memtensor-AI added area:api 云服务 / FastAPI / OpenAPI / MCP status:in-progress Someone or AI is working on it | 人工或 AI 正在处理 labels Oct 13, 2026
@Memtensor-AI

Memtensor-AI commented Oct 13, 2026 •

Copy link
Copy Markdown
Collaborator

🤖 Open Code Review

Target: PR #2491
Task: a04c4f05e24ca076
Base: dev-v2.0.36
Head: fix/issue-2427-canonical-hex

✅ OpenCodeReview: Review complete: 0 finding(s) across 2 selected item(s).

Generated by cloud-assistant via Open Code Review.

@Memtensor-AI

Copy link
Copy Markdown
Collaborator

✅ Automated Test Results: PASSED

All tests passed (21/21 executed). memos_python_core/changed-repo-python: 21/21. Duration: 9s

Branch: fix/issue-2427-canonical-hex

@Memtensor-AI Memtensor-AI added status:ready Ready for implementation; waiting for assignee or AI dispatch | 可进入实现,等待认领或派发 and removed status:in-progress Someone or AI is working on it | 人工或 AI 正在处理 labels Oct 13, 2026
…sor#2427)

validate_key_format exists as a separate copy in two modules — src/memos/api/utils/api_keys.py (canonical home, used by the key-creation utilities) and src/memos/api/middleware/auth.py (the middleware that gates every authenticated request). Both used `int(hex_part, 16)` to verify the 64-char hex tail, which silently passes for:

- a leading `+` or `-` sign (`int("+a..a", 16)` == ...),
- a `0x` / `0X` prefix (`int("0xa..", 16)` == ...),
- `_` separators (PEP 515: `int("a_a", 16)`),
- surrounding whitespace.

So the documented format `krlk_<64-lowercase-hex>` was not actually enforced — keys like `krlk_+a..a`, `krlk_0x..`, or `krlk_a_a` were accepted by the middleware, hashed verbatim, and looked up against the database, bypassing the canonical form that `generate_api_key()` produces.

This commit:

- Replaces the `int(hex_part, 16)` check in the canonical api_keys.py
  implementation with an anchored regex (`[0-9a-f]{64}`) so only the exact
  lowercase 64-hex form is valid.
- Imports the fixed implementation into auth.py and keeps the public
  `validate_key_format` name as a thin re-export, so the middleware
  shares the same logic as the canonical utils copy. This prevents the
  two copies from drifting again — the original bug class.

New tests/api/test_validate_key_format.py covers 21 cases:

- canonical format and `generate_api_key()` output always pass
- 15 non-canonical variants are rejected (signs, 0x prefix, underscore,
  uppercase, whitespace, wrong length, missing prefix, empty)
- both copies (utils and middleware) enforce the same contract

Fixes MemTensor#2427.
@RerankerGuo
RerankerGuo force-pushed the fix/issue-2427-canonical-hex branch from ba76840 to 981130c Compare October 27, 2026 18:52
@Memtensor-AI Memtensor-AI added status:in-progress Someone or AI is working on it | 人工或 AI 正在处理 and removed status:ready Ready for implementation; waiting for assignee or AI dispatch | 可进入实现,等待认领或派发 labels Oct 27, 2026
@RerankerGuo

Copy link
Copy Markdown
Contributor Author

Thanks @endxxxx for the review.

This PR tightens validate_key_format to the canonical hex form for API keys, so a key that is not in canonical format is rejected up front rather than silently accepted. The tests added for #2427 cover the accepted and rejected forms.

@Memtensor-AI

Copy link
Copy Markdown
Collaborator

✅ Automated Test Results: PASSED

All tests passed (21/21 executed). memos_python_core/changed-repo-python: 21/21. Duration: 16s

Branch: fix/issue-2427-canonical-hex

@Memtensor-AI Memtensor-AI added status:ready Ready for implementation; waiting for assignee or AI dispatch | 可进入实现,等待认领或派发 and removed status:in-progress Someone or AI is working on it | 人工或 AI 正在处理 labels Oct 28, 2026
@endxxxx
endxxxx merged commit db41eb5 into MemTensor:dev-v2.0.36 Oct 29, 2026
18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:api 云服务 / FastAPI / OpenAPI / MCP status:ready Ready for implementation; waiting for assignee or AI dispatch | 可进入实现,等待认领或派发

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants