Auditoría Aumentada — DataFlow Analytics API
Grafo de código · SARIF (Semgrep + CodeQL) · weAudit (Alice García) · Blast Radius + Taint
Análisis completado · 2026-06-16
7 Críticos
11 Altos
8 Medios
5 Bajos / Notas
3 No matcheados

Workflow de Aumentación

Paso 1 — Grafo construido + Pre-análisis
engine.preanalysis() completado · 47 nodos · taint tracking activo · blast radius calculado
Paso 2 — Archivos SARIF y weAudit localizados
results_semgrep.sarif · results_codeql.sarif · .vscode/alice.weaudit
Paso 3 — Aumentación ejecutada
matched_findings: 31 · unmatched_findings: 3 (fuera de scope) · subgraphs_created: 12
Paso 4 — Hallazgos y subgrafos inspeccionados
engine.findings() devuelve 31 nodos anotados · 12 subgrafos disponibles
Paso 5 — Cruce con pre-análisis
sarif:error ∩ tainted = 5 nodos críticos · sarif:error ∩ high_blast_radius = 4 nodos · 2 privilege_boundary comprometidos

Salida de Augmentation Engine

CLI Output
# Paso 1: Pre-análisis
$ uv run trailmark preanalysis api/ --language python
→ 47 nodes parsed · taint sources: 8 · blast radius computed

# Paso 3: Aumentación con ambas fuentes
$ uv run trailmark augment api/ \
    --sarif results_semgrep.sarif --sarif results_codeql.sarif \
    --weaudit .vscode/alice.weaudit --json

{
  "matched_findings": 31,
  "unmatched_findings": 3,
  "subgraphs_created": [
    "sarif:error", "sarif:warning", "sarif:note",
    "sarif:semgrep", "sarif:codeql",
    "weaudit:high", "weaudit:medium", "weaudit:low",
    "weaudit:findings", "weaudit:notes",
    "weaudit:alice_garcia"
  ],
  "annotations_added": 31,
  "taint_overlap": 14,
  "blast_radius_overlap": 9
}

Hallazgos Prioritarios — sarif:error ∩ tainted ∩ high_blast_radius

SQL Injection via parámetro no sanitizado
Critical python.lang.security.sqli.raw-query-format-string Semgrep
La función execute_raw_query() construye queries SQL concatenando directamente request.query_params["filter"] sin parameterización. Un atacante puede extraer o modificar cualquier tabla de la BD.
📄 api/routes/query.py · líneas 45–67
☣ Tainted — flujo desde HTTP input 💥 Blast radius: ALTO (23 nodos alcanzables) 🔒 Privilege boundary cruzado
Server-Side Request Forgery (SSRF) en exportación
Critical python.requests.security.ssrf-via-requests-get CodeQL weAudit: Alice
export_to_url() realiza requests.post(user_provided_url, data=payload) sin validar el esquema ni el rango IP de destino. Confirmado por auditora humana: permite exfiltrar metadatos de AWS EC2 (169.254.169.254).
📄 api/routes/export.py · líneas 23–41
☣ Tainted — URL desde body JSON 💥 Blast radius: ALTO (18 nodos)
Deserialización insegura con pickle en caché Redis
Critical python.lang.security.deserialization.pickle Semgrep
cache.get_cached() usa pickle.loads() sobre datos de Redis sin verificar firma. Si un atacante tiene acceso a Redis (o a la red interna), puede ejecutar código arbitrario en el servidor.
📄 api/utils/cache.py · líneas 12–28
☣ Tainted — Redis data sin firmar 💥 Blast radius: MUY ALTO (31 nodos) 🔒 Privilege boundary
Clave JWT hardcodeada en código fuente
High python.jwt.security.jwt-hardcoded-secret CodeQL weAudit: Alice
jwt_handler.py usa SECRET_KEY = "dataflow-secret-2024" hardcodeado. Cualquier persona con acceso al repo puede forjar tokens de autenticación válidos para cualquier usuario.
📄 api/auth/jwt_handler.py · líneas 8–10
🔒 Privilege boundary — autenticación 💥 Blast radius: ALTO (todos los usuarios)
Mass Assignment en modelo de usuario
High python.sqlalchemy.security.mass-assignment weAudit: Alice
El endpoint de actualización de perfil pasa el body JSON directamente a User(**request.json()) sin lista blanca de campos, permitiendo que un usuario normal eleve su propio role a "admin".
📄 api/models/user.py · líneas 54–72
☣ Tainted — JSON body sin filtrar 🔒 Privilege boundary escalación ✓ Solo hallazgo humano — SAST no detectó
Grafo de Código — Subgrafo sarif:error ∩ tainted
Trailmark Visualization
sarif:error
tainted
high_blast_radius
privilege_boundary
weaudit:alice_garcia
nodo limpio
FastAPI router 🔒 execute_raw _query() query.py:45 export_to _url() export.py:23 db.execute( raw_sql) CWE-89 💥 ! jwt_handler .verify() CWE-798 🔒 cache.get _cached() cache.py:12 PostgreSQL ⚠ sqli reachable External URL ⚠ SSRF JWT decode hardcoded key Redis / pickle CWE-502
📊 Cobertura por Archivo
Archivo Hallazgos Riesgo
api/routes/query.py 5 critical
CRÍTICO
api/utils/cache.py 4 critical
CRÍTICO
api/routes/export.py 3 high
ALTO
api/auth/jwt_handler.py 2 high
ALTO
api/models/user.py 3 medium
MEDIO
🎯 Matriz de Triaje — Cruce pre-análisis
Hallazgos en intersección de sarif:error ∩ tainted ∩ high_blast_radius
☣💥🔒 execute_raw_query — SQLi + taint + blast + priv P0
☣💥 get_cached (pickle.loads) — taint + blast máximo P0
☣💥 export_to_url — SSRF + taint externo P0
🔒 jwt_handler — hardcoded secret + priv boundary P1
User mass assignment — taint JSON body P1
Logging de tokens en request.py (warning) P2
Ausencia de rate limiting en /query P3

Anotaciones en Grafo — Formato Trailmark

# engine.annotations_of("execute_raw_query")
[
  {
    "kind": "finding",
    "source": "sarif:semgrep",
    "description": "[ERROR] python.lang.security.sqli.raw-query-format-string: Raw SQL format string (Semgrep)",
    "location": { "file": "api/routes/query.py", "line_start": 45, "line_end": 67 }
  },
  {
    "kind": "finding",
    "source": "sarif:codeql",
    "description": "[ERROR] CWE-89: SQL query built from user-controlled source (CodeQL)",
    "location": { "file": "api/routes/query.py", "line_start": 52, "line_end": 61 }
  }
]

# Subgraph overlap — sarif:error ∩ tainted:
→ 5 nodos comunes: execute_raw_query, get_cached, export_to_url,
build_filter_clause, deserialize_redis_value