Skip to content

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

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

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

Conversation

@seonghobae

@seonghobae seonghobae commented Aug 9, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • reject NUL, non-text C0 controls, and DEL at the ApplySqlIn request-schema boundary while preserving tab, LF, CR, Unicode, and the existing size limit
  • redact raw rejected inputs from application-wide FastAPI 422 validation responses so SQL and credential-bearing values are not reflected
  • document the transport/log-integrity boundary and preserve the existing deterministic DDL allowlist as the execution authority
  • close the pre-existing owned-coverage branch gaps with focused regression tests

Test-first evidence

  • RED: 91 focused failures before the validator/response handler existed
  • GREEN: 102 passed for schema and connection API tests
  • full backend: 474 passed, 1 skipped
  • owned production statement/branch coverage: 100.00% (414 statements, 64 branches)
  • mypy: Success: no issues found in 68 source files
  • git diff --check: clean

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

Closes #764

Summary by CodeRabbit

  • 보안 강화
    • SQL 입력에서 허용되지 않은 제어 문자를 차단합니다.
    • 검증 오류 응답과 로그에 원본 입력값이 노출되지 않습니다.
    • 기존 보안 헤더 값은 필요 없이 덮어쓰지 않습니다.
  • 버그 수정
    • 멀티라인·유니코드 SQL과 허용된 개행 문자가 원문 그대로 처리됩니다.
    • 프로젝트 멤버 역할 및 데이터베이스 연결 정보 검증을 개선했습니다.
  • 문서
    • SQL 전송 검증 범위, 오류 처리 및 보안 기준을 문서화했습니다.

@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown

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: 20 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 66a51551-0dc2-46f9-a947-a73d59d90bca

📥 Commits

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

📒 Files selected for processing (3)
  • backend/tests/test_api_connections.py
  • backend/tests/test_pooler.py
  • docs/security/apply-sql-transport-validation.md
📝 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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목은 멀티라인 SQL에서 비텍스트 제어 문자를 거부하는 핵심 변경을 정확하고 간결하게 설명합니다.
Linked Issues check ✅ Passed [#764] 제어 문자 거부, 허용 문자 보존, 입력값 비노출, 경계 테스트, 문서 갱신 요구를 구현과 테스트로 충족합니다.
✨ 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
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