Skip to content

fix(security): harden bounded JSON input handling - #528

Merged
seonghobae merged 44 commits into
mainfrom
sentinel-json-dos-scripts-17708564860587448239
Aug 4, 2026
Merged

fix(security): harden bounded JSON input handling#528
seonghobae merged 44 commits into
mainfrom
sentinel-json-dos-scripts-17708564860587448239

Conversation

@seonghobae

@seonghobae seonghobae commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Summary

Consolidates repository automation JSON reads behind a shared descriptor-safe loader. The loader bounds accepted input to 32 MiB, rejects structural nesting beyond 128 levels before recursive decoding, requires strict UTF-8 and an object root, and uses descriptor identity checks to reject non-regular inputs and detectable leaf-path replacement.

All eight affected automation scripts delegate to the shared contract. Deterministic tests cover byte and depth boundaries, delimiters and escapes inside strings, malformed and invalid-UTF-8 input, decoder recursion, non-object roots, symlink/FIFO/directory rejection where supported, descriptor/path replacement, and delegation. Public docstrings, authoritative documentation, APA-style references, an authoritative changelog fragment, and the generated CHANGELOG.md entry are included.

Threat boundary

This is bounded-input hardening for local and CI artifact readers. It reduces uncontrolled resource-consumption and recursive-decoder availability risk. It does not make arbitrary JSON semantically trustworthy, replace operating-system permissions, or authorize processing from a hostile writable parent directory.

Validation

  • Focused security/delegation suite: 100% statement and branch coverage for the shared loader
  • Exact-head CI, Security Scan, SAST Semgrep, packaging, Rust workspace, GPU parity, and fuzz checks required before merge

References

MITRE. (2026, April 30). CWE-400: Uncontrolled resource consumption (CWE Version 4.20).

MITRE. (2026, April 30). CWE-674: Uncontrolled recursion (CWE Version 4.20).

Python Software Foundation. (2026). json—JSON encoder and decoder (Python 3.12.13 documentation).

Python Software Foundation. (2026). os—Miscellaneous operating system interfaces (Python 3.12.13 documentation).

Summary by CodeRabbit

  • New Features
    • Added secure, bounded JSON loading for automation workflows.
    • Inputs are validated for file safety, encoding, format, size, and nesting depth.
  • Bug Fixes
    • Improved handling of malformed, oversized, deeply nested, or unsafe JSON inputs with clear errors.
  • Documentation
    • Added security guidance and changelog entries describing validation limits and rejected input types.
  • Tests
    • Added comprehensive coverage for valid boundaries, invalid files, parsing failures, and security protections.

@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 Aug 4, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

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

Next review available in: 35 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 57422a7e-5010-4b40-9a1c-7623b17a0836

📥 Commits

Reviewing files that changed from the base of the PR and between 9cd69b5 and 7f69dfe.

📒 Files selected for processing (3)
  • scripts/build_figma_evidence_sync.py
  • tests/test_bounded_json_scripts.py
  • tests/test_figma_evidence_sync.py
📝 Walkthrough

Walkthrough

A shared descriptor-safe JSON reader now enforces 32 MiB input and 128-level nesting limits. Governed scripts use the reader. Tests cover filesystem safety, parsing failures, limits, and delegation. Documentation records the security contract.

Changes

Bounded JSON hardening

Layer / File(s) Summary
Shared bounded JSON reader
scripts/_bounded_json.py
Adds descriptor validation, bounded reads, UTF-8 decoding, iterative depth checks, object-root enforcement, and explicit errors.
Script adoption and behavior preservation
scripts/build_*.py, scripts/sales_readiness.py
Routes governed _read_json implementations through read_json_object. Existing report generation, validation, orchestration, serialization, and CLI behavior remains unchanged.
Security validation and documentation
tests/test_bounded_json_scripts.py, docs/bounded_json_input_security.md, CHANGELOG.md, docs/changelog.d/*
Adds deterministic tests for limits, invalid content, unsafe files, path replacement, and wrapper delegation. Documents the reader contract and security changes.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 34.04% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main security change: hardening bounded JSON input handling.
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.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch sentinel-json-dos-scripts-17708564860587448239

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

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/build_figma_evidence_sync.py`:
- Around line 50-56: Update all seven _read_json implementations in
scripts/build_figma_evidence_sync.py (anchor lines 50-56),
scripts/build_benchmark_report.py (17-23), scripts/build_buyer_packet.py
(51-57), scripts/build_commercial_release.py (44-50),
scripts/build_procurement_due_diligence.py (42-48),
scripts/build_release_evidence_index.py (30-36), and scripts/sales_readiness.py
(244-250) to enforce a maximum JSON nesting depth before or during json.loads.
Use a shared depth-aware parser or validator that correctly ignores brackets
inside strings and escaped characters, while preserving the existing 32 MiB read
limits and normal JSON parsing for valid inputs.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: fc1fbd7c-e3fc-45e1-8ffd-122154a56bcb

📥 Commits

Reviewing files that changed from the base of the PR and between 320ae3c and 145c937.

📒 Files selected for processing (7)
  • scripts/build_benchmark_report.py
  • scripts/build_buyer_packet.py
  • scripts/build_commercial_release.py
  • scripts/build_figma_evidence_sync.py
  • scripts/build_procurement_due_diligence.py
  • scripts/build_release_evidence_index.py
  • scripts/sales_readiness.py

Comment thread scripts/build_figma_evidence_sync.py Outdated

@seonghobae seonghobae left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@jules Rebuild this PR on the current main before merge and address the exact-head security review. The present head is conflicted and repeats a previously rejected pattern from #388.

Required changes:

  1. Replace the seven duplicated _read_json implementations with one documented shared loader under scripts/ (use a descriptive two-token module/function name). Preserve a 32 MiB byte cap and a conservative nesting cap (the package already uses 128) while correctly ignoring delimiters inside JSON strings and escaped characters.
  2. Harden file opening, not only parsing: open the leaf with O_CLOEXEC, O_NONBLOCK, and O_NOFOLLOW where supported; validate the opened descriptor with fstat as a regular file; read at most the limit plus one byte through that same descriptor; reject symlinks/FIFOs/directories and oversized or invalid UTF-8 input before json.loads. Avoid a path stat()/open() TOCTOU gap. Preserve deterministic, content-free errors.
  3. Use the shared loader in every affected script. Keep each script's existing object-shape contract, including explicitly validating sales_readiness.py input as a JSON object rather than returning arbitrary JSON.
  4. Add complete public docstrings and deterministic tests covering: exact-limit acceptance, limit+1 rejection, depth-boundary acceptance, over-depth rejection, brackets/escaped quotes inside strings, invalid UTF-8, malformed JSON, non-object JSON at each wrapper contract, symlink rejection (when supported), FIFO/non-regular rejection without blocking, and descriptor/path replacement behavior. Do not weaken the repository's 100% statement/branch coverage gate.
  5. Add an authoritative changelog fragment and regenerate CHANGELOG.md. Update the PR description to avoid the unsupported CRITICAL severity claim: these are local/CI artifact readers, so describe the bounded-input hardening and threat assumptions conservatively.
  6. Rebase or otherwise rebuild the branch on the exact current main; do not carry temporary workflows or unrelated changes. Rerun exact-head CI, Security Scan, SAST, and CodeRabbit review.

Resolve the CodeRabbit depth thread only after the shared implementation and tests cover it.

Copy link
Copy Markdown
Contributor Author

@jules Please address the unresolved CodeRabbit CWE-674 finding on the exact current head. Keep the existing 32 MiB bounded read, but consolidate all eight repository automation _read_json implementations (including build_pr_queue_governance.py) behind one documented non-recursive helper that rejects object/array nesting deeper than 128 before json.loads, while correctly ignoring delimiters inside strings and honoring JSON escape state. Preserve strict UTF-8 decoding and object-root validation. Add deterministic tests for exact/oversized byte limits, depth boundary and over-limit nesting, brackets/escaped quotes inside strings, malformed syntax, invalid UTF-8, non-object roots, decoder RecursionError, and delegation by every affected script. Require 100% statement and branch coverage for the added helper. Bring the branch current with main, update authoritative CHANGELOG material and security documentation with APA 7 references to Python's JSON warning and MITRE CWE-674, remove the temporary .github/workflows/one-time-bounded-json-hardening.yml, run focused and repository validation, then push the fixes. Do not resolve the review thread until the exact-head checks pass.

@seonghobae seonghobae left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@jules The current head is not acceptable and must not be merged. Remove .github/workflows/one-time-bounded-json-hardening.yml and commit the actual implementation directly. The generated helper in that workflow still uses path.open("rb"), so it retains the exact symlink/FIFO/path-replacement problems previously rejected in #388 and explicitly called out in my review. It also lacks the required symlink, FIFO/non-regular, and descriptor/path-replacement tests.

Implement the descriptor-safe shared loader itself on this branch: os.open with O_CLOEXEC | O_NONBLOCK | O_NOFOLLOW where available, fstat regular-file validation, lstat/descriptor identity validation, bounded reads from the same descriptor, then UTF-8/depth/JSON/object validation. Commit the real helper, delegation edits, tests, changelog/docs, and updated conservative PR metadata directly. Do not add or retain any temporary workflow. Resolve the existing CodeRabbit thread only after the real exact-head code and tests address it.

Comment thread .github/workflows/one-time-bounded-json-runner.yml Fixed
Comment thread .github/workflows/one-time-bounded-json-runner.yml Fixed

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

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

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

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

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

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.

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/build_figma_evidence_sync.py`:
- Around line 411-413: Update main() to compute out_dir using the same
repository-root base resolution as build_figma_evidence_sync(), then use that
shared directory for both the reported out path and manifest path. Add a
regression test covering a relative --out with --repo-root different from the
current working directory, asserting the returned manifest path exists.

In `@tests/test_bounded_json_scripts.py`:
- Around line 36-50: Add an escaped-quote case to
test_exact_size_depth_strings_escapes_and_unicode, including structural
delimiters after the escaped quote within a valid JSON string. Keep the existing
exact-size and depth assertions, and ensure the expected object reflects the
added string content so read_json_object verifies delimiters are ignored while
inside the escaped-quote string.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 49878f93-4901-48e5-b62d-b2b95b2aa789

📥 Commits

Reviewing files that changed from the base of the PR and between 145c937 and 9cd69b5.

📒 Files selected for processing (13)
  • CHANGELOG.md
  • docs/bounded_json_input_security.md
  • docs/changelog.d/bounded-json-input-hardening.md
  • scripts/_bounded_json.py
  • scripts/build_benchmark_report.py
  • scripts/build_buyer_packet.py
  • scripts/build_commercial_release.py
  • scripts/build_figma_evidence_sync.py
  • scripts/build_pr_queue_governance.py
  • scripts/build_procurement_due_diligence.py
  • scripts/build_release_evidence_index.py
  • scripts/sales_readiness.py
  • tests/test_bounded_json_scripts.py

Comment thread scripts/build_figma_evidence_sync.py Outdated
Comment thread tests/test_bounded_json_scripts.py

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

Please review the exact current head. The previously reported repository-root output-path bug and escaped-quote depth-test gap are addressed, temporary one-time workflows have been removed, and the new regression test is documented. Report only findings still applicable to the current head.

@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

@seonghobae I will review the exact current head. I will report only findings that still apply.

✅ Action performed

Review finished.

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.

@seonghobae
seonghobae enabled auto-merge (squash) August 4, 2026 21:19
@seonghobae
seonghobae merged commit f6d2964 into main Aug 4, 2026
31 of 32 checks passed
@seonghobae
seonghobae deleted the sentinel-json-dos-scripts-17708564860587448239 branch August 4, 2026 21:20
@google-labs-jules

Copy link
Copy Markdown

@jules Please address the unresolved CodeRabbit CWE-674 finding on the exact current head. Keep the existing 32 MiB bounded read, but consolidate all eight repository automation _read_json implementations (including build_pr_queue_governance.py) behind one documented non-recursive helper that rejects object/array nesting deeper than 128 before json.loads, while correctly ignoring delimiters inside strings and honoring JSON escape state. Preserve strict UTF-8 decoding and object-root validation. Add deterministic tests for exact/oversized byte limits, depth boundary and over-limit nesting, brackets/escaped quotes inside strings, malformed syntax, invalid UTF-8, non-object roots, decoder RecursionError, and delegation by every affected script. Require 100% statement and branch coverage for the added helper. Bring the branch current with main, update authoritative CHANGELOG material and security documentation with APA 7 references to Python's JSON warning and MITRE CWE-674, remove the temporary .github/workflows/one-time-bounded-json-hardening.yml, run focused and repository validation, then push the fixes. Do not resolve the review thread until the exact-head checks pass.

요청하신 대로 기존 32 MiB 읽기 제한 및 128 수준의 비재귀적 깊이 제한(문자열 내 대괄호/이스케이프 처리 포함)을 구현한 단일 문서화된 헬퍼 read_json_objectscripts._bounded_json 모듈에 작성하였고, 저장소 자동화 스크립트 8개가 이를 사용하도록 통합했습니다. UTF-8 디코딩 검증과 루트 객체(dict) 검증도 유지됩니다. 관련하여 지정된 모든 예외 조건(크기 초과, 깊이 초과, 잘못된 구문, 잘못된 UTF-8, 루트 타입 오류, 디코더 RecursionError)과 해당 헬퍼를 모든 스크립트가 위임하는지에 대한 결정론적 테스트를 tests/test_bounded_json_scripts.py에 추가하여 구문 및 분기 커버리지 100%를 달성했습니다. 아울러 main 브랜치 변경 사항을 반영하고 권위 있는 문서(docs/bounded_json_input_security.mdCHANGELOG.md)에 Python의 JSON 경고와 MITRE CWE-674를 인용한 APA 7 스타일 참조를 포함하여 업데이트했으며, 임시 워크플로 파일을 삭제했습니다. 모든 변경 후 테스트 스위트가 정상적으로 통과됨을 확인했습니다.

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.

2 participants