Skip to content

Security: gburd/pg_tre

Security

SECURITY.md

Security Policy

Reporting a Vulnerability

If you discover a security vulnerability in pg_tre, please report it responsibly by emailing greg@burd.me with the subject line [pg_tre security].

Please include:

  • A description of the vulnerability.
  • Steps to reproduce.
  • Potential impact.
  • Any suggested fixes (optional).

I will acknowledge receipt within 7 days and aim to provide a fix or mitigation within 30 days for confirmed vulnerabilities.

Please do not disclose the vulnerability publicly until a fix has shipped or 90 days have passed since the initial report, whichever comes first.

Security Considerations

pg_tre is a PostgreSQL extension that runs as part of the backend process and has the same privileges as the PostgreSQL server. When deploying:

  • Follow PostgreSQL security best practices.
  • Limit CREATE EXTENSION privileges to trusted users.
  • Review index configurations before deployment in multi-tenant environments. pg_tre.match_timeout_ms bounds the wall-clock time spent in a single regex match (see "Known Sharp Edges" for exactly what is and is not enforced). pg_tre.max_nfa_states rejects patterns whose compiled automaton is too large before any match runs. pg_tre.compile_timeout_ms bounds the wall-clock time spent compiling a single pattern (enforced since 1.5.6; see below).
  • Keep PostgreSQL and pg_tre updated to the latest versions.
  • Run with wal_consistency_checking = 'pg_tre' enabled in pre-production environments to catch any custom-rmgr WAL redo bugs before they hit production standbys.

Known Sharp Edges

  • The tre_amatch(text, text, int) UDF accepts arbitrary regex patterns and runs them through a TRE backend that has documented worst-case complexity. Two guardrails bound this cost, and it is important to understand precisely what each one does:

    • pg_tre.match_timeout_ms is enforced for the match phase. The matcher's per-input-position NFA loop calls a progress hook (installed by the extension) that compares the current wall-clock time against a deadline armed when the match begins; once the deadline passes, the match is aborted and the query fails with a query_canceled error (pg_tre: regex match exceeded pg_tre.match_timeout_ms). Enforcement granularity is one NFA position-step (effectively sub-millisecond for normal inputs). The legacy tre_amatch* / tre_distance / tre_similarity UDFs arm this deadline automatically. Do not raise the timeout for untrusted callers.

    • pg_tre.max_nfa_states is enforced at pattern-compile time: a pattern whose compiled automaton exceeds the limit is rejected before it can ever reach the match path.

    • pg_tre.compile_timeout_ms is enforced (since 1.5.6) for the pattern-compile phase. A progress hook woven into TRE's NFA-build loops (the bounded-repetition AST expansion and the tag/copy/compile worklists) compares the current wall-clock time against a deadline armed when compilation begins; once the deadline passes, compilation is aborted and the query fails with a query_canceled error (pg_tre: regex compilation exceeded pg_tre.compile_timeout_ms). This closes the compile-time DoS lever (pathological nested bounded repetitions such as a{80}{80}{80} can expand for seconds before max_nfa_states is even evaluated, since the state cap is checked only after the automaton is built). Compilation remains additionally bounded by the 64 KiB hard pattern-length ceiling and by pg_tre.max_nfa_states. Do not raise the timeout for untrusted callers.

  • The per-tuple positional bloom and positional filter (tier-3.1) were removed in 3.0.0. They were lossy CPU pre-filters only; the executor recheck remains authoritative for correctness, so their removal does not change query results. The range bloom (tier-1 heap-block skip) is retained.

Disclosure Acknowledgements

Reporters of confirmed vulnerabilities are credited in CHANGELOG.md under ### Security for the release that fixes the issue, unless the reporter requests anonymity.

There aren't any published security advisories