Skip to content
Closed
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .jules/sentinel.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## 2024-05-24 - [API ํ‚ค ๋น„๊ต 500 ์—๋Ÿฌ ์ฒ˜๋ฆฌ]
**Vulnerability:** HMAC ๋ฌธ์ž์—ด ๋น„๊ต์—์„œ non-ASCII ๋ฌธ์ž๊ฐ€ ์‚ฌ์šฉ๋  ๊ฒฝ์šฐ 500 ์„œ๋ฒ„ ์—๋Ÿฌ(DoS ๊ฐ€๋Šฅ์„ฑ)๊ฐ€ ๋ฐœ์ƒํ•จ.
**Learning:** ํŒŒ์ด์ฌ hmac.compare_digest์— non-ASCII ๋ฌธ์ž์—ด์„ ์ง์ ‘ ์ „๋‹ฌํ•˜๋ฉด TypeError๊ฐ€ ๋ฐœ์ƒํ•จ.
**Prevention:** API ํ‚ค๋ฅผ ๊ฒ€์‚ฌํ•  ๋•Œ ํ•ญ์ƒ ๋ฌธ์ž์—ด์„ UTF-8 ๋ฐ”์ดํŠธ๋กœ ์ธ์ฝ”๋”ฉํ•œ ํ›„ ๋น„๊ตํ•ด์•ผ ํ•จ.


## 2026-07-25 - [Cross-platform upload basename normalization]
**Behavior:** Upload metadata now interprets both forward slashes and backslashes as path separators before extracting a basename.
**Learning:** On POSIX systems, `pathlib.Path(filename).name` retains backslashes because they are ordinary characters there. That caused inconsistent manifest and converter filenames for Windows-style client paths. The upload itself is still written inside a trusted temporary workspace, and batch archive entry names are generated outputs; this change does not establish a filesystem traversal or archive-entry escape.
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@
### Fixed
- ๋‹จ์ผยท์ผ๊ด„ ๋Œ€์ƒ ํฌ๊ธฐ ์ž…๋ ฅ์„ ๋น„์› ์„ ๋•Œ ์ด์ „ custom validity์™€ `aria-invalid` ์ƒํƒœ๋ฅผ ์ฆ‰์‹œ ์ดˆ๊ธฐํ™”ํ•ด ํ˜„์žฌ ํ•„์ˆ˜ ์ž…๋ ฅ ์ƒํƒœ๋ฅผ ์ •ํ™•ํžˆ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.
- ์—…๋กœ๋“œ ํŒŒ์ผ๋ช…์˜ ๊ฒฝ๋กœ ๊ตฌ๋ถ„์ž๋ฅผ ์ •๊ทœํ™”ํ•˜์—ฌ POSIX์—์„œ๋„ Windows ํ˜•์‹์˜ ํด๋ผ์ด์–ธํŠธ ๊ฒฝ๋กœ๊ฐ€ ์ผ๊ด€๋œ basename์œผ๋กœ ๊ธฐ๋ก๋˜๋„๋ก ์ˆ˜์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.
- ๋ณด์•ˆ(Security): API ํ‚ค ๊ฒ€์‚ฌ ์‹œ non-ASCII ๋ฌธ์ž๋กœ ์ธํ•œ 500 ๋‚ด๋ถ€ ์„œ๋ฒ„ ์˜ค๋ฅ˜(DoS ์œ„ํ—˜) ์ˆ˜์ •
2 changes: 1 addition & 1 deletion saas_web.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ async def require_api_key(request: Request, call_next):
if configured_keys and not (request.method == "GET" and request.url.path == "/"):
provided_key = request.headers.get("x-api-key", "")
if not any(
hmac.compare_digest(provided_key, key) for key in configured_keys
hmac.compare_digest(provided_key.encode("utf-8"), key.encode("utf-8")) for key in configured_keys

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

๐Ÿ” Non-ASCII authentication lacks regression coverage

No test exercises compare_digest with a non-ASCII header or configured key. The reported 500-error path can regress unnoticed.

Devin Review

Was this helpful? React with ๐Ÿ‘ or ๐Ÿ‘Ž to provide feedback.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

๐Ÿ” Runtime secrets bypass credential registry

Authentication still sources keys from CODEC_CARVER_API_KEYS. The repository rule requires migrating this known deviation to a credential registry.

Devin Review

Was this helpful? React with ๐Ÿ‘ or ๐Ÿ‘Ž to provide feedback.

):
return JSONResponse(
status_code=401,
Expand Down
Loading