fix(postgres): sanitize all non-identifier chars in table names#48
Merged
Conversation
sanitizeTableName only replaced '-', '.' and ' ' with underscores, so a
collection name containing other characters leaked into the interpolated
CREATE TABLE statement and produced a SQL syntax error.
LocalAI namespaces per-user collections as "{userID}:{name}". Under legacy
API-key auth the userID is the literal "legacy-api-key", so an agent's
collection became "legacy-api-key:<agent>". The ':' was not sanitized and
PostgreSQL rejected the DDL with "syntax error at or near ':'" (SQLSTATE
42601), preventing agents with knowledge base / long-term memory from
creating their vector collection.
Switch to an allowlist: map any character that is not [A-Za-z0-9_] to an
underscore. This guarantees a legal unquoted identifier for any collection
name (covering ':', '/', '@', etc.) while preserving the previous handling
of '-', '.' and ' '. The userID prefix is kept intact, so per-user table
isolation on a shared database is unaffected.
Fixes mudler/LocalAI#10375
Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
mudler
added a commit
to mudler/LocalAGI
that referenced
this pull request
Jun 18, 2026
#478) chore: bump localrecall to include PostgreSQL table-name sanitization fix Pulls mudler/LocalRecall#48, which makes sanitizeTableName allowlist valid identifier characters so collection names containing ':' (e.g. the per-user "legacy-api-key:<agent>" namespace used by LocalAI) no longer break PostgreSQL CREATE TABLE with "syntax error at or near ':'". Ref: mudler/LocalAI#10375 Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
mudler
added a commit
to mudler/LocalAI
that referenced
this pull request
Jun 18, 2026
…10375) (#10387) chore: bump localrecall to include PostgreSQL table-name sanitization fix Pulls mudler/LocalRecall#48, which makes sanitizeTableName allowlist valid identifier characters so collection names containing ':' (e.g. the per-user "legacy-api-key:<agent>" namespace) no longer break PostgreSQL CREATE TABLE with "syntax error at or near ':'". Fixes #10375 Signed-off-by: Ettore Di Giacinto <mudler@localai.io> Co-authored-by: Ettore Di Giacinto <mudler@localai.io>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
sanitizeTableNameonly replaced-,.andwith underscores. Any other character in a collection name leaked into the interpolatedCREATE TABLEDDL and produced a SQL syntax error.This surfaced as mudler/LocalAI#10375: LocalAI namespaces per-user collections as
{userID}:{name}. Under legacy API-key auth theuserIDis the literallegacy-api-key, so an agent's collection name becomeslegacy-api-key:<agent>. The:was never sanitized, so:Agents with knowledge base / long-term memory enabled could not create their PostgreSQL collection. (UUID-based user IDs happened to work only because hyphens were in the replace set.)
Fix
Switch
sanitizeTableNamefrom a hardcoded denylist to an allowlist: map any character that is not[A-Za-z0-9_]to_. This guarantees a legal unquoted PostgreSQL identifier for any collection name (:,/,@, etc.), while preserving the previous handling of-,.and.The
userIDprefix is kept intact, so per-user table isolation on a shared database is preserved - this only makes the existing namespacing scheme PostgreSQL-safe.Tests
Added
rag/engine/sanitize_test.go(Ginkgo, internal package, no DB required)::separator),Red → green confirmed; package builds and vets clean.