7.1 KiB
Sprint 10 — C2 TLS verify: redteam-friendly defaults + warning suppression
Base: origin/main (PR #11 merged — sprint 8 + 9 are in).
Branch: sprint/10-c2-tls-default.
Scope: tiny correctness sprint. No new feature. Flip a security-relevant default to match the actual operator usage of this tool.
Symptom (user report)
"Impossible de se connecter à mon C2 à cause de la vérification du certificat SSL (self signed)"
Operator opens C2 config card, fills URL + token, hits Test connection without noticing the checkbox → SSL VERIFY FAILED against self-signed Mythic.
Root cause (workflow diagnosis confirmed)
The verify_tls chain is fully intact end-to-end :
React verifyTls state → C2ConfigInput.verify_tls → PUT body → C2Config.verify_tls column → cfg.verify_tls in API loader → get_adapter(verify_tls=) → MythicAdapter._verify → requests.post(verify=self._verify).
The bug is the default at every layer is True :
backend/app/models/c2_config.py:22—default=Truebackend/migrations/versions/0006_c2_layer.py:29—server_default=sa.true()backend/app/api/c2.py:87—data.get("verify_tls", True)backend/app/services/c2/mythic.py:116—verify_tls: bool = Truebackend/app/services/c2/factory.py:9—verify_tls=Truefrontend/src/components/C2ConfigCard.tsx:27—useState(true)frontend/src/components/C2ConfigCard.tsx:74— reset on deletesetVerifyTls(true)
Mimic is a BAS / red-team lab tool ; the dominant case is a self-signed Mythic instance, not a publicly-trusted cert chain. Defaulting verify=True is hostile to the actual workflow.
Secondary defect : urllib3.exceptions.InsecureRequestWarning is never suppressed (zero hits for disable_warnings / urllib3 in backend/). When operators correctly uncheck verify, stderr gets spammed once per HTTP call.
Decisions (locked)
- Flip default to
Falseat every layer — model, API fallback, adapter, factory, React state, delete reset. - New migration 0008 : flip
server_defaulttosa.false(). Existing rows are NOT mutated (their stored boolean is preserved). - Suppress
urllib3.InsecureRequestWarningONLY whenverify_tls=False— gated insideMythicAdapter.__init__. Keeps the warning live for any future code that legitimately verifies. - Add helper text under checkbox : "Leave unchecked for lab Mythic with self-signed certificates." Operators see why the box matters.
- No API contract change —
C2ConfigInput.verify_tls: booleanstays required. The fallback indata.get("verify_tls", False)only matters for hand-crafted requests.
Out of scope
- Don't touch existing C2 endpoints behavior (route paths, payload shapes).
- Don't change the
verify_tlsfield type or remove the column. - Don't change the FakeAdapter (it makes no HTTP calls).
Task A — Backend (backend-builder)
Files :
backend/app/models/c2_config.py— line 22 :default=True→default=Falsebackend/app/api/c2.py— line 87 :data.get("verify_tls", True)→data.get("verify_tls", False)backend/app/services/c2/factory.py— line 9 :verify_tls: bool = True→verify_tls: bool = Falsebackend/app/services/c2/mythic.py— line 116 :verify_tls: bool = True→verify_tls: bool = False, AND add at top of fileimport urllib3+from urllib3.exceptions import InsecureRequestWarning, AND inside__init__afterself._verify = verify_tls:if not verify_tls: urllib3.disable_warnings(InsecureRequestWarning)- NEW migration
backend/migrations/versions/0008_c2_verify_tls_default_false.py— flipserver_defaulttosa.false(). Useop.batch_alter_table("c2_config")for SQLite compatibility (Mimic uses SQLite per sprint 1 SPEC). Down-migration restoressa.true(). - Tests : grep
backend/tests/forverify_tlsand flip every assertion that presupposed the oldTruedefault (likely intest_c2_config*.pyPUT-without-verify-tls tests and GET-fresh-row tests). Don't add new tests — adapt existing ones.
Constraints :
pytestbaseline 468/468 must hold (or grow ; never shrink).ruff+mypy --strictclean.- Migration 0008 must be reversible — round-trip
alembic upgrade headthenalembic downgrade -1thenalembic upgrade headmust work on a fresh SQLite DB. - Don't restructure or refactor anything else. Minimum surface.
Task B — Frontend (frontend-builder)
Files :
frontend/src/components/C2ConfigCard.tsx:- Line 27 :
useState(true)→useState(false) - Line 74 (delete handler) :
setVerifyTls(true)→setVerifyTls(false) - Under the checkbox JSX (around lines 169-182) : add a
<p>with helper text :(Use the existing DESIGN.md tokens —<p className="text-[12px] text-charcoal mt-xxs"> Leave unchecked for lab Mythic with self-signed certificates. </p>text-[12px] text-charcoalmatches thehintstyle onFormField. Confirm token name by reading neighboring components first.)
- Line 27 :
- Vitest : if
C2ConfigCard.test.tsxexists, flip any "starts checked" assertion to "starts unchecked".
Constraints :
vitestbaseline 212/212 must hold.tsc --noEmit+eslint --max-warnings=0clean.- No type change to
C2ConfigInput(the field is already requiredboolean). - Visual: same row, just one extra
<p>hint below the checkbox-label row. Same brutalist treatment, no transition.
Task C — Sequencing
Both tasks have zero shared files. Dispatch backend-builder + frontend-builder in parallel. No ordering constraint.
After both report green :
- code-reviewer : sprint diff scan (focus : migration reversibility, urllib3 gating, no leftover hardcoded
True). - design-reviewer : helper-text placement, token compliance, focus ring still works, no regression on the card.
- spec-reviewer : verify SPEC.md § Intégration C2 still matches the new defaults (may need a one-line note about lab-mode default ; check before editing).
Definition of Done
- Test connection against self-signed Mythic from a freshly-created C2 config works without unchecking anything.
- Existing rows are untouched (operators who saved verify_tls=true keep it until they re-save).
pytest468/468 → 468+ (no shrink),vitest212/212.ruff+mypy --strict+tsc --noEmit+eslintclean.- Migration 0008 round-trip OK.
- No
urllib3.InsecureRequestWarningon stderr whenverify_tls=False. - Code-reviewer + design-reviewer + spec-reviewer APPROVED.
- PR opened on Gitea ; tasks/pr-body-sprint-10.md drafted by team-lead.
Operator notes (for PR body)
- This sprint flips a security-relevant default. Production operators who legitimately use a publicly-trusted cert chain will need to explicitly check the box — but the dominant case in this BAS tool is lab Mythic with self-signed, so the new default matches the actual workflow.
- Existing engagements with
verify_tls=truealready stored remain unchanged. They keep their current behaviour. If the operator reported the bug because their existing row hasverify_tls=true, they will still need to uncheck + save once after this sprint lands.