Skip to content

Review C: Fix unauthenticated export endpoint, readDocument pool, and pg_ regex - #18

Open
davidpomerenke wants to merge 1 commit into
mainfrom
claude/stoic-feynman-cvojni-c
Open

Review C: Fix unauthenticated export endpoint, readDocument pool, and pg_ regex#18
davidpomerenke wants to merge 1 commit into
mainfrom
claude/stoic-feynman-cvojni-c

Conversation

@davidpomerenke

Copy link
Copy Markdown
Contributor

Summary

Three security/correctness bugs fixed from the code review:

1. Missing auth on POST /api/export/entities

File: src/app/api/export/entities/route.ts

This endpoint generated and returned a formatted Excel file but had no authentication check. Any unauthenticated internet caller could POST arbitrary row data and receive a well-formatted spreadsheet.

Fix: Added getCurrentUser() check at the top of the handler; returns 401 if no session. This matches the auth pattern used by the parallel POST /api/export/survey endpoint.

2. readDocument() used the main admin DB pool

File: src/lib/chat-tools.ts

readDocument() was calling query() (the main admin connection pool) instead of chatQuery() (the restricted read-only pool). Since the AI chat system is supposed to operate with reduced DB privileges for defense-in-depth, all chat tool functions should use chatQuery. Both pools set the same search_path, so the query result is identical — only the privilege level changes.

Fix: Changed query<...>(...)chatQuery<...>(...) in readDocument().

3. isQuerySafe() regex didn't block pg_* functions

File: src/lib/chat-tools.ts

The pg_ entry in the dangerous keywords array used \bpg_\b as the regex. Because _ is a word character in JavaScript regex, \b does not match between g and _. As a result, pg_read_file, pg_ls_dir, pg_largeobject etc. all passed the safety check.

Fix: Moved pg_ out of the word-boundary regex loop and added a dedicated includes('pg_') check on the lowercased SQL string before the loop. Defense-in-depth still applies (the chat_readonly DB user lacks pg_* privileges), but the application-layer filter now correctly blocks these patterns too.

Test plan

  • curl -X POST /api/export/entities without a session cookie → expect 401
  • With a valid session → should still return the Excel file
  • Verify isQuerySafe('SELECT pg_read_file(\'/etc/passwd\')') now returns { safe: false }
  • Verify isQuerySafe('SELECT * FROM documents') still returns { safe: true }

🤖 Generated with Claude Code


Generated by Claude Code

@vercel

vercel Bot commented Jun 19, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
un80-sg-reports-survey Error Error Jun 19, 2026 6:27am

Request Review

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.

1 participant