fix(checkpoint-postgres): Replace f-string SQL formatting with parameterized queries in migration statements (#6328)

## Summary

Replace f-string SQL formatting with parameterized queries to prevent
potential SQL injection in checkpoint migration code.

## Changes

Updated the migration version tracking INSERT statements in all
checkpoint saver classes to use parameterized queries instead of
f-string formatting:

- `PostgresSaver`
(libs/checkpoint-postgres/langgraph/checkpoint/postgres/__init__.py:100)
- `AsyncPostgresSaver`
(libs/checkpoint-postgres/langgraph/checkpoint/postgres/aio.py:104-106)
- `ShallowPostgresSaver`
(libs/checkpoint-postgres/langgraph/checkpoint/postgres/shallow.py:255)
- `AsyncShallowPostgresSaver`
(libs/checkpoint-postgres/langgraph/checkpoint/postgres/shallow.py:617-619)

**Before (vulnerable to SQL injection):**
```python
cur.execute(f"INSERT INTO checkpoint_migrations (v) VALUES ({v})")
```

**After (using parameterized query):**
```python
cur.execute("INSERT INTO checkpoint_migrations (v) VALUES (%s)", (v,))
```

## Risk Assessment

The practical risk is low since `v` is an integer loop variable
controlled by the codebase. However, using string formatting in SQL
queries is a well-known anti-pattern that can lead to SQL injection
vulnerabilities, especially if the code is later refactored or copied to
other contexts.

## Testing

- ✅ All 216 tests passing on PostgreSQL 15 and 16
- ✅ Linting and type checking passing
- ✅ No functional changes to behavior
This commit is contained in:
Cole Murray
2025-11-07 08:00:10 -05:00
committed by GitHub
parent c2ef3f3fd3
commit b0a1029d55
3 changed files with 8 additions and 4 deletions
@@ -97,7 +97,7 @@ class PostgresSaver(BasePostgresSaver):
strict=False,
):
cur.execute(migration)
cur.execute(f"INSERT INTO checkpoint_migrations (v) VALUES ({v})")
cur.execute("INSERT INTO checkpoint_migrations (v) VALUES (%s)", (v,))
if self.pipe:
self.pipe.sync()
@@ -102,7 +102,9 @@ class AsyncPostgresSaver(BasePostgresSaver):
strict=False,
):
await cur.execute(migration)
await cur.execute(f"INSERT INTO checkpoint_migrations (v) VALUES ({v})")
await cur.execute(
"INSERT INTO checkpoint_migrations (v) VALUES (%s)", (v,)
)
if self.pipe:
await self.pipe.sync()
@@ -252,7 +252,7 @@ class ShallowPostgresSaver(BasePostgresSaver):
strict=False,
):
cur.execute(migration)
cur.execute(f"INSERT INTO checkpoint_migrations (v) VALUES ({v})")
cur.execute("INSERT INTO checkpoint_migrations (v) VALUES (%s)", (v,))
if self.pipe:
self.pipe.sync()
@@ -614,7 +614,9 @@ class AsyncShallowPostgresSaver(BasePostgresSaver):
strict=False,
):
await cur.execute(migration)
await cur.execute(f"INSERT INTO checkpoint_migrations (v) VALUES ({v})")
await cur.execute(
"INSERT INTO checkpoint_migrations (v) VALUES (%s)", (v,)
)
if self.pipe:
await self.pipe.sync()