Saltar al contenido

Volver a la documentacióndocs/security/THREAT_MODEL.mdRepositorio privado

Threat model / Modelo de amenazas

Scope: the Centinela platform itself (ingestion, analysis, decision, execution planes, UI, deployment and supply chain). Method: STRIDE per component plus an agent-specific analysis. Every threat lists its mitigations and the test or control that verifies it (test names are real; CI runs them as blocking suites: security.yml → injection-suite, ci.yml).

Assets to protect: customer inventories (metadata), findings and plans, signing keys, approval attestations, the executor's GitHub App credentials, the audit chain, tenant isolation, and — above all — the guarantee that nothing executes without a valid human approval.

1. Agent-specific threats

#ThreatMitigationsVerified by
A1Prompt injection via CVE text, advisories, READMEs, resource names, tags, commit messages, tool resultsUntrusted wrapper cannot be concatenated into prompts (core); render_untrusted() wraps content in per-request random-boundary blocks and escapes breakouts; system prompts declare block content as data; heuristic + classifier detector logs/alerts; deterministic post-LLM validation independent of the model (closed catalog, tenant asset existence, fixed-version existence, path patterns, no shell text)packages/core/tests/test_untrusted.py; packages/agent/tests/test_prompting_injection_redaction.py::test_render_untrusted_wraps_and_neutralises_breakouts, ::test_injection_heuristics_flag_known_patterns; packages/agent/tests/test_validator.py::test_validator_rejects_out_of_scope_content, ::test_bump_without_known_fixed_version_rejected; evals injection suite (100 % no out-of-catalog actions)
A2Tool abuse — model invokes a mutating tool or reads another tenantthe tool registry contains read-only tools only and is frozen; every tool is tenant-scoped; the agent process holds no write credentials (IAM analysis boundary denies the executor queue, KMS Sign restricted to plan-signer)packages/agent/tests/test_tools_schemas.py; Terraform iam-workload-identities boundaries; Checkov in CI
A3Exfiltration through the model (secrets/PII in prompts, model output leaking to the world)inventory holds metadata only (data reads denied by IAM); secret/PII redactor before every prompt; Bedrock via VPC endpoint with no training retention; egress allowlisttest_redaction_removes_secrets_and_pii; packages/connectors IAM simulator tests (policy_sim.py) asserting s3:GetObject, secretsmanager:GetSecretValue, kms:Decrypt, logs:GetLogEvents denied; Network Firewall drop_rest + blocked-egress alarm
A4Confused deputy — a plan references assets of another tenant or a repository not linked to the findingvalidator checks node ownership by tenant and repo↔asset linkage; Postgres RLS; executor re-checks via freshness endpoint scoped to the plan's tenanttest_validator_rejects_out_of_scope_content; packages/graph/tests::test_cross_tenant_isolation; apps/api/tests cross-tenant 404s
A5Model produces invalid or hallucinated output (versions that do not exist, free-form commands)structured output with JSON Schema; up to 3 retries then needs_manual_analysis; target versions must exist as fixed versions in the vulnerability sourcetest_bump_without_known_fixed_version_rejected; packages/agent/tests/test_pipeline.py
A6Feed poisoning — a tampered or malicious advisoryraw records stored; integrity verification where providers offer it; the matcher is deterministic and never changes affectedness based on text; VEX statements only suppress with recorded evidence; KEV/EPSS used as signals, never as instructionsfeed connector tests (fixtures); packages/matcher golden precision/recall ≥ 0.95
A7Approval abuse (self-approval, machine approval, chat approvals, replay, approving a different plan version)SoD in OPA and API; machine identities never approvers; no approval buttons outside the UI; WebAuthn challenge bound to the plan hash, ≤ 5 min; attestation bound to content_hash; any plan change voids attestations; two-person rule for P0 prod; executor re-verifies everythingRego: test_approval_by_requester_is_invalid, test_actor_cannot_approve_twice, test_approval_without_webauthn_is_invalid, test_approval_with_hash_mismatch_is_invalid, test_comment_required_for_p0_p1; API: test_approver_cannot_be_requester, test_machine_identity_never_approves, test_platform_admin_cannot_approve, test_modifier_cannot_approve_new_version; executor: TestSecurity_AttestationBoundToPlan, TestSecurity_ModifiedPlanFails, TestSecurity_P0ProdTwoPersonWithLeadIsAccepted
A8Insider with platform access tries to execute without approval or to silence the audit trailplatform_admin cannot approve; executor only consumes the queue whose only producer is approval-service; append-only audit with hash chain + Object Lock; break-glass needs double activation and alertstest_platform_admin_cannot_approve; TestSecurity_ExecutionGateDenials; packages/audit/tests::test_detects_modified_event, ::test_segment_verification_detects_segment_tampering; test_break_glass_needs_tenant_flag_and_two_activations

2. STRIDE per component

Ingestion plane (feeds, collectors, repo scanner)

STRIDEThreatMitigationVerified by
SSpoofed feed/webhookTLS + allowlisted hosts; GitHub webhook HMAC (X-Hub-Signature-256); provider integrity checksconnectors webhook signature tests
TTampered inventory (fake resources via tags)tags/labels are Untrusted; provenance recorded per fact; reconciliation declared-vs-realgraph reconcile tests
RUnknown origin of a factProvenance(source, observed_at, reference) on every node/edgecore model tests
ICollector reads customer datacustom read-only policy + permissions boundary with explicit denies; separate SBOM rolespolicy_sim.py tests; CFN/Terraform policies
DFeed outage / rate limitscursors, backoff, DLQs, SLO monitorsconnector backoff tests; Datadog monitors
ERepo scanner executes repository code (sandbox escape)static analysis only; allowlisted analyzers; no network except GitHub; no cloud env; read-only FS; destroyed aftersandbox tests (non-allowlisted command rejected; env has no cloud credentials)

Analysis plane (matcher, risk, agent, plan-signer)

STRIDEThreatMitigationVerified by
SForged planKMS plan-signer key: Sign only by the plan-signer role; verify everywherepackages/signing/tests::test_wrong_key_and_wrong_role_fail; TestSecurity_WrongKeyAndCrossSignerRejected
TPlan modified after signingcontent_hash over canonical JSON; signaturetest_modified_plan_after_signing_fails; TestSecurity_ModifiedPlanFails
R"Who scored this?"policy_version, model_id, prompts/responses in audit (redacted)risk engine tests on policy versioning
ISecrets in promptsredaction; metadata-only inventorytest_redaction_removes_secrets_and_pii
DToken budget exhaustionper-tenant/per-finding budgets, monitorspackages/agent/budget.py tests
EAgent gains write pathIAM boundary denies SQS send to executor queue + KMS Sign except plan-signer; no write toolsTerraform boundaries; test_tools_schemas.py

Decision plane (api, approval-service, OPA, UI, notifier)

STRIDEThreatMitigationVerified by
SSession/OIDC token forgery; WebAuthn replayJWKS verification (iss/aud/exp/kid), short sessions, assertion counter, hash-bound challengeapps/api/tests/test_webauthn*; test_approve_without_webauthn_is_rejected
TCSRF / clickjacking on approvaldouble-submit CSRF, strict CSP, frame-ancestors none, hold-to-confirm + WebAuthnAPI CSRF tests; UI tests (ApprovalPanel cannot confirm without diff)
RDisputed approvalsigned attestation with approver id, auth method, assertion id, timestampattestation tests
ICross-tenant data accessRLS forced + store-level filter; per-tenant keystest_cross_tenant_isolation; API 404 tests
DApproval spam / rateper-user+tenant rate limiting; execution hourly limit; WAF rate rulesAPI rate-limit tests; waf-ui module
ERole escalation (platform_admin approving)RBAC matrix in Rego + API dependencytest_platform_admin_cannot_approve; test_analyst_can_triage_but_not_approve

Execution plane (executor)

STRIDEThreatMitigationVerified by
SMessage injected into the queuequeue policy: single producer; message type pinned; both signatures verified with pinned keysTerraform queues; TestSecurity_UnsignedExpiredBadAlgorithm
TTOCTOU — target changed after analysisinventory_snapshot_id + expected_file_sha freshness checks → staleexecutor freshness tests (TestSecurity_Rejections)
RUntraceable executionevery gate step emits an audit event; idempotency key per actionexecutor audit sink tests
IExecutor reads customer data / LLMIAM executor boundary denies Bedrock, S3 GetObject, DB; no LLM SDK linkedTerraform boundary; TestSecurity_NoShellOrExecInExecutor
DRunaway executionshourly rate limit in policy; kill switch (file/ConfigMap + epoch); Recreate strategytest_kill_switch_blocks_queueing_but_records_approval; executor kill-switch tests
EExecutor merges / changes protection / runs shellGitHub App without admin permission; client has no merge/approve/protection methods; no os/execTestSecurity_NoMergeApproveOrProtectionCode; TestSecurity_NoShellOrExecInExecutor; app manifest permission set

Audit

STRIDEThreatMitigationVerified by
T/REvent altered, deleted or reorderedhash chain, append-only grants + trigger, Object Lock COMPLIANCE, centinela-audit verifytest_detects_modified_event, test_detects_unsealed_and_cross_tenant, test_cli_verify_ok_and_tampered

Supply chain of Centinela itself

ThreatMitigationVerified by
Malicious dependency / actionlockfiles; Dependabot; actions pinned by SHA with weekly drift check; dependency reviewscripts/verify-action-pins.sh; verify-pins.yml; security.yml
Tampered imagecosign keyless signing + SBOM attestation + SLSA L3 provenance; Kyverno admission requires bothrelease.yml; deploy/helm/cluster/kyverno-verify-images.yaml
Secrets in repogitleaks in CI; no static credentials (OIDC, Pod Identity, WIF)security.yml → gitleaks
Vulnerable codeCodeQL + Semgrep + Trivy + ZAP baselinesecurity.yml

3. Residual risks and assumptions

  • GitHub branch protection on target repositories must require CODEOWNERS review; Centinela cannot enforce it on customers' repositories (it detects and reports missing protection as a posture finding).
  • The quality of ownership attribution depends on customer tags/CODEOWNERS; ownerless assets escalate to security_lead by policy.
  • Bedrock Guardrails are optional; the deterministic validator is the primary control.
  • Checkov/HCL validation ran in the authoring environment; tofu validate and real-cloud integration tests run in CI/trusted environments (see docs/STATUS.md).

ES: Modelo STRIDE por componente más amenazas específicas de agentes (inyección de prompts, abuso de herramientas, exfiltración, confused deputy, envenenamiento de feeds, cadena de suministro, abuso de aprobaciones, insider). Cada amenaza indica su mitigación y la prueba que la verifica.