Skip to content

security(api): reject non-text controls in multiline SQL - #832

Open
seonghobae wants to merge 7 commits into
mainfrom
codex/sql-control-validation
Open

security(api): reject non-text controls in multiline SQL#832
seonghobae wants to merge 7 commits into
mainfrom
codex/sql-control-validation

Conversation

@seonghobae

@seonghobae seonghobae commented Aug 9, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • reject NUL, every non-text C0 control, DEL, and the complete C1 block (U+007F–U+009F) at the ApplySqlIn request-schema boundary
  • preserve tab, LF, CR, printable Unicode, and the existing 262,144-character size limit
  • redact raw rejected inputs from application-wide FastAPI 422 validation responses so SQL and credential-bearing values are not reflected
  • preserve the deterministic DDL allowlist as the separate execution authority
  • document the transport/log-integrity boundary and its failure behavior

Test-first evidence

  • original RED: 91 focused failures before the validator/response handler existed
  • C1 extension RED on predecessor fcc908e60d54a8ccfa9c6f2440f1c6984fb52e71: 96 missing beginning/middle/end cases for U+0080–U+009F
  • GREEN: 187 exhaustive apply-SQL control cases; 192 schema-validation tests
  • full backend: 570 passed, 1 skipped
  • changed production module: app/schemas.py 148/148 statements and 2/2 branches (100%)
  • mypy: clean across 68 source files
  • git diff --check: clean

The first local full-suite probe inherited the sandbox SOCKS proxy and failed only three Clearfolio HTTPX constructors because the hash-locked environment intentionally lacks socksio; removing uppercase and lowercase proxy transport variables produced the full green result above, matching CI’s test boundary.

No dependency, lockfile, database migration, frontend, or workflow changes.

Closes #764.

@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

ApplySqlIn이 허용된 공백과 Unicode를 보존하면서 비텍스트 제어 문자와 DEL을 거부합니다. FastAPI 422 검증 응답은 원본 입력을 제거합니다. 관련 테스트와 보안 문서를 추가하고 기존 권한, DSN, 헤더 동작을 검증합니다.

Changes

SQL 전송 보안

Layer / File(s) Summary
ApplySqlIn 제어 문자 검증
backend/app/schemas.py
탭, LF, CR과 Unicode는 유지하고 비텍스트 C0 제어 문자 및 DEL이 포함된 SQL은 거부합니다.
검증 오류 응답 정제
backend/app/main.py
RequestValidationError 처리기가 원본 input을 제거하고 안전한 오류 정보만 HTTP 422 응답에 포함합니다.
SQL 검증 수용 기준과 문서
backend/tests/test_schema_validation.py, backend/tests/test_api_connections.py, docs/security/apply-sql-transport-validation.md, CHANGELOG.md
허용 문자 보존, 제어 문자 위치별 거부, 응답과 로그의 원문 제거를 검증하고 변경 내용을 문서화합니다.

기존 동작 회귀 검증

Layer / File(s) Summary
기존 동작 회귀 테스트
backend/tests/test_permissions.py, backend/tests/test_pooler.py, backend/tests/test_security_headers.py
최소 역할이 없는 viewer 검증, pgcat DSN 생성, 기존 X-Frame-Options 값 보존을 검증합니다.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant FastAPI
  participant ApplySqlIn
  participant redact_request_validation_input
  Client->>FastAPI: /apply-sql 요청
  FastAPI->>ApplySqlIn: sql 필드 검증
  ApplySqlIn-->>FastAPI: ValidationError
  FastAPI->>redact_request_validation_input: RequestValidationError 전달
  redact_request_validation_input-->>Client: 입력값이 제거된 422 응답
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning [#764]와 직접 관련 없는 권한, 풀러 DSN, 보안 헤더 테스트 변경이 포함되어 범위를 벗어납니다. 관련 없는 test_permissions.py, test_pooler.py, test_security_headers.py 변경을 별도 PR로 분리하거나 제거하십시오.
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Linked Issues check ✅ Passed [#764] 제어 문자 거부, 허용 문자 보존, 입력값 비노출, 경계 테스트, 문서 갱신 요구를 구현과 테스트로 충족합니다.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목은 멀티라인 SQL에서 비텍스트 제어 문자를 거부하는 주요 보안 변경을 정확하고 간결하게 설명합니다.
✨ 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 codex/sql-control-validation

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.

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown
✅ 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

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
docs/security/apply-sql-transport-validation.md (1)

35-45: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

문헌별 근거 요약을 추가하십시오.

현재 References에는 인용과 링크가 있지만 각 문헌이 어떤 검증 경계를 뒷받침하는지 설명이 없습니다. 각 참조 아래에 이 PR의 JSON transport, PostgreSQL lexical 처리, 또는 Unicode control-character 분류와의 관련성을 한 문장으로 추가하십시오.

As per coding guidelines, substantive pull requests must provide relevant citations, links, and summaries when permissible paper PDFs are not attached.

🤖 Prompt for 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.

In `@docs/security/apply-sql-transport-validation.md` around lines 35 - 45, 각 참고문헌
항목 아래에 해당 자료가 뒷받침하는 검증 경계를 한 문장으로 요약하십시오. Bray의 RFC 8259는 JSON transport 검증,
PostgreSQL 문헌은 lexical 처리, Unicode 표준은 control-character 분류와 연결되도록 작성하고 기존 인용 및
링크는 유지하십시오.

Source: Coding guidelines

🤖 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 `@backend/tests/test_api_connections.py`:
- Around line 192-200: Ruff S105를 피하도록 테스트의 하드코딩된 비밀번호 marker를 여러 비밀이 아닌 문자열
조각으로 분리하십시오. test_api_connections의 해당 테스트에서 조각을 결합해 SQL의 credential 기본값을 만들고,
동일한 결합 값을 응답 및 로그 비노출 assertion에 재사용하십시오.

In `@backend/tests/test_pooler.py`:
- Around line 41-47: Update the test input surrounding the DSN construction so
the PostgreSQL URL is assembled at runtime from non-sensitive components rather
than committed as a full DSN containing credentials and connection details.
Remove the hardcoded password literal and the `# noqa: S105` suppression while
preserving the existing DSN and password assertions.

---

Nitpick comments:
In `@docs/security/apply-sql-transport-validation.md`:
- Around line 35-45: 각 참고문헌 항목 아래에 해당 자료가 뒷받침하는 검증 경계를 한 문장으로 요약하십시오. Bray의 RFC
8259는 JSON transport 검증, PostgreSQL 문헌은 lexical 처리, Unicode 표준은
control-character 분류와 연결되도록 작성하고 기존 인용 및 링크는 유지하십시오.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 5386a4d2-f966-40fa-838e-100bbbdae878

📥 Commits

Reviewing files that changed from the base of the PR and between 72afe6d and 1f8b859.

📒 Files selected for processing (9)
  • CHANGELOG.md
  • backend/app/main.py
  • backend/app/schemas.py
  • backend/tests/test_api_connections.py
  • backend/tests/test_permissions.py
  • backend/tests/test_pooler.py
  • backend/tests/test_schema_validation.py
  • backend/tests/test_security_headers.py
  • docs/security/apply-sql-transport-validation.md

Comment thread backend/tests/test_api_connections.py Outdated
Comment thread backend/tests/test_pooler.py Outdated

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

Please review the unchanged exact head fcc908e60d54a8ccfa9c6f2440f1c6984fb52e71. All prior inline findings are resolved and CI, Security Scan, and SAST Semgrep pass on this head.

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown

@seonghobae I will run a full review of PR #832 at commit fcc908e60d54a8ccfa9c6f2440f1c6984fb52e71. This review will re-evaluate the existing changes.

⚠️ Action not completed

Review rate limited.


Your included review limit is currently reached under our Fair Usage Limits Policy. This review may still proceed through usage-based billing if eligible. Your next included review will be available in 35 minutes.

Copy link
Copy Markdown
Collaborator Author

Exact-current-head independent review request for fcc908e60d54a8ccfa9c6f2440f1c6984fb52e71.

@opencode-agent @cwl-noema-review Please provide a qualifying non-author review of this unchanged predecessor. CI 31320017558, Security Scan 31320017576, and SAST Semgrep 31320017539 are terminal-success on this SHA, and there are zero unresolved review threads. CodeRabbit's last retry was rate-limited and is not approval evidence. Do not mutate the branch or merge.

Copy link
Copy Markdown
Collaborator Author

Exact-current-head independent review request for 5bf6cc56ca4e80d89fed852362a6ae4f8717be98.

@opencode-agent @cwl-noema-review Please review this unchanged exact head and provide a qualifying non-author formal verdict. Current-head CI 31479659678, Security Scan 31479659654, and SAST Semgrep 31479659679 are terminal-success; all prior inline threads are resolved. The successor adds exhaustive C1 (U+0080–U+009F) rejection coverage and implementation without changing the deterministic DDL execution authority.

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.

security(api): reject non-text controls in multiline SQL requests

1 participant