Skip to content

fix seed SSRF - #942

Open
ZohaibHassan16 wants to merge 3 commits into
mainfrom
fix-seed-api-ssrf
Open

fix seed SSRF#942
ZohaibHassan16 wants to merge 3 commits into
mainfrom
fix-seed-api-ssrf

Conversation

@ZohaibHassan16

Copy link
Copy Markdown
Collaborator

Summary

Fixed SSRF issue in SeedDataManager.load_from_api().

Previously it was directly using requests.get() with the user provided API URL. Now it uses the existing request_with_ssrf_guard() helper.

Changes

  • Replaced direct requests.get() call with request_with_ssrf_guard()
  • Blocks localhost, private IPs, link-local IPs and cloud metadata endpoints
  • Redirects are checked too, so a public URL cannot redirect to an internal URL
  • Updated API loading test to mock the SSRF helper
  • Added tests for:
    • Direct loopback URL blocking
    • Redirect to cloud metadata endpoint blocking

Testing

pytest tests/test_seed_manager.py tests/ingest/test_ssrf_protection.py -q

@qodo-code-review

Copy link
Copy Markdown

ⓘ Qodo reviews are paused because the subscription is no longer active. Ask your workspace admin to reactivate the subscription to resume reviews. Manage billing

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Harden SeedDataManager API loading with SSRF-guarded requests

🐞 Bug fix 🧪 Tests 🕐 20-40 Minutes

Grey Divider

AI Description

• Route seed API fetching through shared SSRF guard instead of direct requests.get
• Prevent access to loopback/private/link-local and metadata endpoints (including redirects)
• Extend seed manager tests to cover blocked loopback and redirect-to-metadata cases
Diagram

graph TD
  A(["SeedDataManager.load_from_api"]) --> B[["request_with_ssrf_guard" (ingest/ssrf.py)]] --> C{"URL allowed?"}
  C -- "No" --> G[/"Raise ValidationError\n(wrapped as ProcessingError)"/]
  C -- "Yes" --> E[/"requests.request\n(allow_redirects=false)"/] --> F[/"Remote API"/] --> H{"Redirect?"}
  H -- "No" --> A
  H -- "Yes" --> B

  subgraph Legend
    direction LR
    _svc(["Caller"]) ~~~ _mod[["Helper module"]] ~~~ _dec{"Decision"} ~~~ _ext[/"External"/]
  end
Loading
High-Level Assessment

Using the existing request_with_ssrf_guard() is the right approach: it centralizes SSRF policy (including redirect re-validation) and avoids duplicating security-sensitive logic inside SeedDataManager.

Files changed (2) +51 / -10

Bug fix (1) +7 / -6
seed_manager.pyUse SSRF-guarded HTTP helper for seed API loading +7/-6

Use SSRF-guarded HTTP helper for seed API loading

• Replaces the direct requests.get() call in SeedDataManager.load_from_api() with the shared request_with_ssrf_guard() helper. Updates the method docstring to explicitly describe SSRF-protected fetching (including redirect protection).

semantica/seed/seed_manager.py

Tests (1) +44 / -4
test_seed_manager.pyUpdate API-loading tests for SSRF guard + add SSRF block coverage +44/-4

Update API-loading tests for SSRF guard + add SSRF block coverage

• Updates the existing load_from_api test to mock request_with_ssrf_guard() and assert correct invocation. Adds tests ensuring loopback URLs are blocked without issuing a network request and that redirects to the cloud metadata IP are blocked after the initial safe host resolves.

tests/test_seed_manager.py

@github-actions

Copy link
Copy Markdown

🔒 Security Scan Results

Safety — dependency vulnerabilities

✅ No findings.

Bandit — HIGH-severity code issues

✅ No findings.

Semgrep — static analysis patterns

Found 55.

Show all findings
  • python.lang.security.audit.non-literal-import.non-literal-import in semantica/__init__.py:58
  • python.lang.security.audit.dynamic-urllib-use-detected.dynamic-urllib-use-detected in semantica/cli.py:735
  • python.lang.security.audit.insecure-file-permissions.insecure-file-permissions in semantica/cli.py:3868
  • python.lang.security.audit.insecure-file-permissions.insecure-file-permissions in semantica/cli.py:4002
  • python.lang.security.audit.non-literal-import.non-literal-import in semantica/ingest/__init__.py:271
  • python.lang.security.audit.formatted-sql-query.formatted-sql-query in semantica/ingest/databricks_ingestor.py:506
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/ingest/databricks_ingestor.py:506
  • python.sqlalchemy.security.audit.avoid-sqlalchemy-text.avoid-sqlalchemy-text in semantica/ingest/db_ingestor.py:310
  • python.sqlalchemy.security.audit.avoid-sqlalchemy-text.avoid-sqlalchemy-text in semantica/ingest/db_ingestor.py:331
  • python.lang.security.audit.formatted-sql-query.formatted-sql-query in semantica/ingest/duckdb_ingestor.py:99
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/ingest/duckdb_ingestor.py:99
  • python.lang.security.audit.formatted-sql-query.formatted-sql-query in semantica/ingest/duckdb_ingestor.py:165
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/ingest/duckdb_ingestor.py:165
  • python.lang.security.audit.formatted-sql-query.formatted-sql-query in semantica/ingest/duckdb_ingestor.py:242
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/ingest/duckdb_ingestor.py:242
  • python.lang.security.audit.formatted-sql-query.formatted-sql-query in semantica/ingest/duckdb_ingestor.py:342
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/ingest/duckdb_ingestor.py:342
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/ingest/snowflake_ingestor.py:542
  • python.lang.security.audit.formatted-sql-query.formatted-sql-query in semantica/ingest/snowflake_ingestor.py:732
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/ingest/snowflake_ingestor.py:732
  • python.lang.security.audit.formatted-sql-query.formatted-sql-query in semantica/ingest/snowflake_ingestor.py:748
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/ingest/snowflake_ingestor.py:748
  • python.lang.security.audit.formatted-sql-query.formatted-sql-query in semantica/ingest/snowflake_ingestor.py:813
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/ingest/snowflake_ingestor.py:813
  • python.lang.security.audit.hardcoded-password-default-argument.hardcoded-password-default-argument in semantica/kg/graph_builder.py:965
  • python.lang.security.audit.formatted-sql-query.formatted-sql-query in semantica/provenance/storage.py:506
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/provenance/storage.py:506
  • python.lang.security.audit.formatted-sql-query.formatted-sql-query in semantica/provenance/storage.py:509
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/provenance/storage.py:509
  • python.lang.security.audit.formatted-sql-query.formatted-sql-query in semantica/provenance/storage.py:512
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/provenance/storage.py:512
  • python.lang.security.audit.formatted-sql-query.formatted-sql-query in semantica/provenance/storage.py:513
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/provenance/storage.py:513
  • python.lang.security.audit.formatted-sql-query.formatted-sql-query in semantica/provenance/storage.py:575
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/provenance/storage.py:575
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/provenance/storage.py:828
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/provenance/storage.py:927
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/provenance/storage.py:950
  • python.lang.security.audit.non-literal-import.non-literal-import in semantica/semantic_extract/__init__.py:137
  • python.lang.security.audit.non-literal-import.non-literal-import in semantica/utils/helpers.py:508
  • python.lang.security.audit.non-literal-import.non-literal-import in semantica/utils/helpers.py:510
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/vector_store/pgvector_store.py:498
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/vector_store/pgvector_store.py:579
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/vector_store/pgvector_store.py:618
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/vector_store/pgvector_store.py:752
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/vector_store/pgvector_store.py:900
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/vector_store/pgvector_store.py:927
  • python.lang.security.audit.formatted-sql-query.formatted-sql-query in semantica/vector_store/sqlite_vec_store.py:240
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/vector_store/sqlite_vec_store.py:240
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/vector_store/sqlite_vec_store.py:311
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/vector_store/sqlite_vec_store.py:402
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/vector_store/sqlite_vec_store.py:454
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/vector_store/sqlite_vec_store.py:689
  • python.lang.security.audit.formatted-sql-query.formatted-sql-query in semantica/vector_store/sqlite_vec_store.py:732
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/vector_store/sqlite_vec_store.py:732

This security scan runs automatically on source-code PRs and bi-weekly (skipped for doc/markdown-only changes).

📊 Security Policy: CI fails on Safety vulnerabilities and Bandit HIGH-severity findings. Semgrep findings above are informational and do not block merge.

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (0) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. No private-IP escape hatch 🐞 Bug ≡ Correctness
Description
SeedDataManager.load_from_api() now always uses request_with_ssrf_guard() with its default
allow_private_ips=False, so any seed API hosted on private/loopback/link-local ranges will always be
blocked (even in trusted internal deployments). This is inconsistent with other HTTP ingestors that
expose an explicit allow_private_ips configuration and can cause legitimate internal seeding
workflows to fail after this change.
Code

semantica/seed/seed_manager.py[R494-496]

+            response = request_with_ssrf_guard(
+                "GET", full_url, headers=request_headers, timeout=30
+            )
Evidence
The seed manager call site passes only method/url/headers/timeout, so request_with_ssrf_guard()
runs with its default allow_private_ips=False, which triggers blocking logic in
validate_url_for_request() for loopback/private/link-local hosts. Other ingestors explicitly pass
an allow_private_ips value, showing that the guard is designed to support trusted opt-ins.

semantica/seed/seed_manager.py[481-497]
semantica/ingest/ssrf.py[164-223]
semantica/ingest/ssrf.py[225-246]
semantica/ingest/api_ingestor.py[159-177]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`SeedDataManager.load_from_api()` now routes requests through `request_with_ssrf_guard()`, which blocks private/loopback/link-local targets unless `allow_private_ips=True`. The seed manager does not expose any parameter/config to opt into private IP fetching for trusted internal deployments, unlike other ingest clients.

### Issue Context
- `request_with_ssrf_guard(..., allow_private_ips: bool = False, ...)` defaults to blocking private/loopback/link-local targets.
- `RESTIngestor` passes `allow_private_ips=self.allow_private_ips` into the helper, indicating a supported escape hatch pattern.

### Fix Focus Areas
- Add an explicit opt-in control (parameter and/or config) and pass it through to `request_with_ssrf_guard`.
- Keep the secure default (`False`) so public/default behavior remains SSRF-safe.
- Update unit tests to reflect the additional kwarg (and optionally add a test proving opt-in works).

Recommended implementation options:
1) Add `allow_private_ips: Optional[bool] = None` to `load_from_api(...)`, where `None` means “use manager config default”.
2) Read a config key like `seed_allow_private_ips` (or reuse a shared `allow_private_ips`) and pass it through.

### Fix Focus Areas (code references)
- semantica/seed/seed_manager.py[439-497]
- tests/test_seed_manager.py[150-205]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Tip of the day
💡 Did you know, you can enable the Remediation agent and Qodo fixes findings in a dedicated fix PR

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread semantica/seed/seed_manager.py
@ZohaibHassan16

Copy link
Copy Markdown
Collaborator Author

Qodo bot's finding is irrelevant to this PR and that is intentional for this PR.

allow_private_ips needs its own API/config design and documentation. I think it is better handled in a separate follow-up issue instead of expanding this security fix.

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Qodo bot's finding is irrelevant to this PR and that is intentional for this PR.

allow_private_ips needs its own API/config design and documentation. I think it is better handled in a separate follow-up issue instead of expanding this security fix.

Understood. The current PR review index contains no active findings, so there is nothing here to dismiss. Treating allow_private_ips as a separate API/configuration and documentation follow-up is reasonable; this PR can remain scoped to enforcing SSRF protections by default.

@github-actions

Copy link
Copy Markdown

🔒 Security Scan Results

Safety — dependency vulnerabilities

✅ No findings.

Bandit — HIGH-severity code issues

✅ No findings.

Semgrep — static analysis patterns

Found 55.

Show all findings
  • python.lang.security.audit.non-literal-import.non-literal-import in semantica/__init__.py:58
  • python.lang.security.audit.dynamic-urllib-use-detected.dynamic-urllib-use-detected in semantica/cli.py:735
  • python.lang.security.audit.insecure-file-permissions.insecure-file-permissions in semantica/cli.py:3868
  • python.lang.security.audit.insecure-file-permissions.insecure-file-permissions in semantica/cli.py:4002
  • python.lang.security.audit.non-literal-import.non-literal-import in semantica/ingest/__init__.py:271
  • python.lang.security.audit.formatted-sql-query.formatted-sql-query in semantica/ingest/databricks_ingestor.py:506
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/ingest/databricks_ingestor.py:506
  • python.sqlalchemy.security.audit.avoid-sqlalchemy-text.avoid-sqlalchemy-text in semantica/ingest/db_ingestor.py:310
  • python.sqlalchemy.security.audit.avoid-sqlalchemy-text.avoid-sqlalchemy-text in semantica/ingest/db_ingestor.py:331
  • python.lang.security.audit.formatted-sql-query.formatted-sql-query in semantica/ingest/duckdb_ingestor.py:99
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/ingest/duckdb_ingestor.py:99
  • python.lang.security.audit.formatted-sql-query.formatted-sql-query in semantica/ingest/duckdb_ingestor.py:165
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/ingest/duckdb_ingestor.py:165
  • python.lang.security.audit.formatted-sql-query.formatted-sql-query in semantica/ingest/duckdb_ingestor.py:242
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/ingest/duckdb_ingestor.py:242
  • python.lang.security.audit.formatted-sql-query.formatted-sql-query in semantica/ingest/duckdb_ingestor.py:342
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/ingest/duckdb_ingestor.py:342
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/ingest/snowflake_ingestor.py:542
  • python.lang.security.audit.formatted-sql-query.formatted-sql-query in semantica/ingest/snowflake_ingestor.py:732
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/ingest/snowflake_ingestor.py:732
  • python.lang.security.audit.formatted-sql-query.formatted-sql-query in semantica/ingest/snowflake_ingestor.py:748
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/ingest/snowflake_ingestor.py:748
  • python.lang.security.audit.formatted-sql-query.formatted-sql-query in semantica/ingest/snowflake_ingestor.py:813
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/ingest/snowflake_ingestor.py:813
  • python.lang.security.audit.hardcoded-password-default-argument.hardcoded-password-default-argument in semantica/kg/graph_builder.py:965
  • python.lang.security.audit.formatted-sql-query.formatted-sql-query in semantica/provenance/storage.py:506
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/provenance/storage.py:506
  • python.lang.security.audit.formatted-sql-query.formatted-sql-query in semantica/provenance/storage.py:509
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/provenance/storage.py:509
  • python.lang.security.audit.formatted-sql-query.formatted-sql-query in semantica/provenance/storage.py:512
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/provenance/storage.py:512
  • python.lang.security.audit.formatted-sql-query.formatted-sql-query in semantica/provenance/storage.py:513
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/provenance/storage.py:513
  • python.lang.security.audit.formatted-sql-query.formatted-sql-query in semantica/provenance/storage.py:575
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/provenance/storage.py:575
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/provenance/storage.py:828
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/provenance/storage.py:927
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/provenance/storage.py:950
  • python.lang.security.audit.non-literal-import.non-literal-import in semantica/semantic_extract/__init__.py:137
  • python.lang.security.audit.non-literal-import.non-literal-import in semantica/utils/helpers.py:508
  • python.lang.security.audit.non-literal-import.non-literal-import in semantica/utils/helpers.py:510
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/vector_store/pgvector_store.py:498
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/vector_store/pgvector_store.py:579
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/vector_store/pgvector_store.py:618
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/vector_store/pgvector_store.py:752
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/vector_store/pgvector_store.py:900
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/vector_store/pgvector_store.py:927
  • python.lang.security.audit.formatted-sql-query.formatted-sql-query in semantica/vector_store/sqlite_vec_store.py:240
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/vector_store/sqlite_vec_store.py:240
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/vector_store/sqlite_vec_store.py:311
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/vector_store/sqlite_vec_store.py:402
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/vector_store/sqlite_vec_store.py:454
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/vector_store/sqlite_vec_store.py:689
  • python.lang.security.audit.formatted-sql-query.formatted-sql-query in semantica/vector_store/sqlite_vec_store.py:732
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/vector_store/sqlite_vec_store.py:732

This security scan runs automatically on source-code PRs and bi-weekly (skipped for doc/markdown-only changes).

📊 Security Policy: CI fails on Safety vulnerabilities and Bandit HIGH-severity findings. Semgrep findings above are informational and do not block merge.

@KaifAhmad1
KaifAhmad1 requested a review from Sameer6305 August 12, 2026 17:38
@github-actions

Copy link
Copy Markdown

🔒 Security Scan Results

Safety — dependency vulnerabilities

✅ No findings.

Bandit — HIGH-severity code issues

✅ No findings.

Semgrep — static analysis patterns

Found 55.

Show all findings
  • python.lang.security.audit.non-literal-import.non-literal-import in semantica/__init__.py:58
  • python.lang.security.audit.dynamic-urllib-use-detected.dynamic-urllib-use-detected in semantica/cli.py:735
  • python.lang.security.audit.insecure-file-permissions.insecure-file-permissions in semantica/cli.py:3868
  • python.lang.security.audit.insecure-file-permissions.insecure-file-permissions in semantica/cli.py:4002
  • python.lang.security.audit.non-literal-import.non-literal-import in semantica/ingest/__init__.py:271
  • python.lang.security.audit.formatted-sql-query.formatted-sql-query in semantica/ingest/databricks_ingestor.py:506
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/ingest/databricks_ingestor.py:506
  • python.sqlalchemy.security.audit.avoid-sqlalchemy-text.avoid-sqlalchemy-text in semantica/ingest/db_ingestor.py:310
  • python.sqlalchemy.security.audit.avoid-sqlalchemy-text.avoid-sqlalchemy-text in semantica/ingest/db_ingestor.py:331
  • python.lang.security.audit.formatted-sql-query.formatted-sql-query in semantica/ingest/duckdb_ingestor.py:99
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/ingest/duckdb_ingestor.py:99
  • python.lang.security.audit.formatted-sql-query.formatted-sql-query in semantica/ingest/duckdb_ingestor.py:165
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/ingest/duckdb_ingestor.py:165
  • python.lang.security.audit.formatted-sql-query.formatted-sql-query in semantica/ingest/duckdb_ingestor.py:242
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/ingest/duckdb_ingestor.py:242
  • python.lang.security.audit.formatted-sql-query.formatted-sql-query in semantica/ingest/duckdb_ingestor.py:342
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/ingest/duckdb_ingestor.py:342
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/ingest/snowflake_ingestor.py:542
  • python.lang.security.audit.formatted-sql-query.formatted-sql-query in semantica/ingest/snowflake_ingestor.py:732
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/ingest/snowflake_ingestor.py:732
  • python.lang.security.audit.formatted-sql-query.formatted-sql-query in semantica/ingest/snowflake_ingestor.py:748
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/ingest/snowflake_ingestor.py:748
  • python.lang.security.audit.formatted-sql-query.formatted-sql-query in semantica/ingest/snowflake_ingestor.py:813
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/ingest/snowflake_ingestor.py:813
  • python.lang.security.audit.hardcoded-password-default-argument.hardcoded-password-default-argument in semantica/kg/graph_builder.py:1048
  • python.lang.security.audit.formatted-sql-query.formatted-sql-query in semantica/provenance/storage.py:506
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/provenance/storage.py:506
  • python.lang.security.audit.formatted-sql-query.formatted-sql-query in semantica/provenance/storage.py:509
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/provenance/storage.py:509
  • python.lang.security.audit.formatted-sql-query.formatted-sql-query in semantica/provenance/storage.py:512
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/provenance/storage.py:512
  • python.lang.security.audit.formatted-sql-query.formatted-sql-query in semantica/provenance/storage.py:513
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/provenance/storage.py:513
  • python.lang.security.audit.formatted-sql-query.formatted-sql-query in semantica/provenance/storage.py:575
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/provenance/storage.py:575
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/provenance/storage.py:828
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/provenance/storage.py:927
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/provenance/storage.py:950
  • python.lang.security.audit.non-literal-import.non-literal-import in semantica/semantic_extract/__init__.py:137
  • python.lang.security.audit.non-literal-import.non-literal-import in semantica/utils/helpers.py:508
  • python.lang.security.audit.non-literal-import.non-literal-import in semantica/utils/helpers.py:510
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/vector_store/pgvector_store.py:498
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/vector_store/pgvector_store.py:579
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/vector_store/pgvector_store.py:618
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/vector_store/pgvector_store.py:752
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/vector_store/pgvector_store.py:900
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/vector_store/pgvector_store.py:927
  • python.lang.security.audit.formatted-sql-query.formatted-sql-query in semantica/vector_store/sqlite_vec_store.py:240
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/vector_store/sqlite_vec_store.py:240
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/vector_store/sqlite_vec_store.py:311
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/vector_store/sqlite_vec_store.py:402
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/vector_store/sqlite_vec_store.py:454
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/vector_store/sqlite_vec_store.py:689
  • python.lang.security.audit.formatted-sql-query.formatted-sql-query in semantica/vector_store/sqlite_vec_store.py:732
  • python.sqlalchemy.security.sqlalchemy-execute-raw-query.sqlalchemy-execute-raw-query in semantica/vector_store/sqlite_vec_store.py:732

This security scan runs automatically on source-code PRs and bi-weekly (skipped for doc/markdown-only changes).

📊 Security Policy: CI fails on Safety vulnerabilities and Bandit HIGH-severity findings. Semgrep findings above are informational and do not block merge.

@Sameer6305 Sameer6305 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified the fix end-to-end against upstream/main. The original SSRF vulnerability is confirmed, and the change to request_with_ssrf_guard() correctly closes the affected path.

I also verified the redirect protection, DNS/IP validation, blocked internal addresses, and relevant error handling. The focused tests and existing SSRF coverage pass successfully, with no blocking regressions found.

I found a few unrelated pre-existing issues during the review as well:

  • Authorization headers can be forwarded across cross-origin redirects.
  • The caller-provided headers dictionary can be mutated when adding Authorization.
  • There is a now-unnecessary except (ImportError, OSError) around the old lazy requests import.

These are outside the scope of this PR, so I’ll file separate issues for them.

The PR is correct and approved from my side.

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.

2 participants