Divan-e-Cyber

As with cybersecurity, interpretation and attribution count.

  • CTEM Part 2

    “Fix Verification Isn’t a Code Review. It’s a Risk Decision.”

    by Mona Ghadiri


    Part 1 of this series ended with a question: for your last ten AI-remediated findings, was the fix scanned before it merged?

    If that question made you uncomfortable, this part is for you.

    The instinct most security teams reach for is more review. Better review. Senior engineer on the diff. Mandatory approval gate. That instinct is wrong – not because review doesn’t matter, but because it’s answering the wrong question.

    A code review tells you whether a fix looks correct. It does not tell you whether the fix is safe.

    Those are different questions. Conflating them is where AI-assisted remediation workflows break down.


    Two Ways a Fix Can Fail

    When an AI proposes a remediation, there are two distinct failure modes. Most verification processes are only built to catch one of them.

    Failure mode one: semantic incorrectness.
    The fix is syntactically valid and passes tests, but doesn’t actually resolve the root cause. It addresses the symptom. A reviewer with a strong mental model of the code might catch this. A reviewer working with AI-generated code they didn’t write and don’t fully understand probably won’t. The diff looks clean. The underlying logic is still broken.

    Failure mode two: fix-introduced vulnerability.
    The remediation itself contains new exploitable code. This is the failure mode Part 1 introduced. It doesn’t require the original fix to be wrong – the fix can correctly address the original finding and still introduce something new. A code review is not designed to catch this. It requires the same class of agentic scanning that caught the original vulnerability.

    Traditional CTEM programs have implicit controls for failure mode one – code review, peer approval, testing. They have almost no controls for failure mode two. Because until recently, the remediation was human-written code that went through the same development process as everything else. The assumption was reasonable.

    It isn’t anymore.


    Why “Have a Human Review It” Isn’t a Control

    A control is only as strong as the assumption it rests on.

    Code review as a verification mechanism rests on this assumption: the reviewer has sufficient comprehension of the code to independently evaluate the fix. For human-written code in a well-understood codebase, that assumption usually holds.

    For AI-generated code fixing AI-introduced vulnerabilities, it holds less often than security teams realize, and the gap widens as codebases scale. AI-generated code increases as a percentage of total volume, and as the vulnerability classes being fixed move from well-understood patterns toward complex business logic.

    The reviewer is not failing at their job. They are being asked to verify something using a tool – human judgment – that wasn’t designed for the input they’re receiving.

    This is not an argument against code review. It’s an argument that code review is necessary but not sufficient, and that treating it as sufficient is a control gap in your CTEM mobilization stage.


    The Tier Model

    Not every AI-proposed fix carries the same verification burden. Treating them all the same wastes capacity on low-risk remediations and under-invests in high-risk ones.

    The decision rule is straightforward: verification tier is determined by the intersection of fix complexity and asset criticality.

    Tier 1: Automated rescan gate

    Applies when:

    • The vulnerability class is well-understood (dependency version bump, known injection pattern, standard cryptographic weakness)
    • The fix pattern is established and the change is bounded in scope
    • The asset is not internet-exposed or does not have a path to sensitive data

    Verification mechanism: MDASH runs as a post-fix pipeline gate before PR merge. The fix does not merge until it passes a clean scan. No human escalation required beyond standard code review.

    This covers the majority of AI-proposed fixes by volume. It’s fast, it’s automated, and it closes failure mode two without adding review overhead.

    Tier 2: Senior practitioner review

    Applies when any of the following are true:

    • The fix touches authentication, authorization, or session management code
    • The underlying code is AI-generated and no human has a complete mental model of the logic
    • The asset is internet-exposed with a path to sensitive data
    • The vulnerability class involves business logic rather than a known pattern
    • The fix scope is broad – multiple files, multiple functions, architectural change

    Verification mechanism: Automated rescan gate plus explicit senior practitioner sign-off against defined criteria. The practitioner is not reviewing the diff for correctness alone – they are making a risk judgment about whether the fix complexity exceeds the team’s ability to independently verify semantic correctness.

    If it does, that’s an escalation, not a failure. It means the finding stays open until the verification burden can be met.


    The Decision Rule in Practice

    The tier assignment question is: does a human reviewer have sufficient comprehension of this code to independently evaluate whether the fix is semantically correct?

    If yes, Tier 1 with automated rescan is sufficient.

    If no, or if the asset criticality means the cost of being wrong is high, Tier 2.

    This sounds simple. The operational challenge is that most teams don’t have a defined threshold for “sufficient comprehension.” They have a vague norm that senior engineers review complex changes. That norm doesn’t translate into a repeatable decision rule, and it doesn’t account for AI-generated code specifically.

    Define the threshold explicitly. Write it down. Make it part of your CTEM mobilization criteria, not a judgment call made differently by every reviewer.


    What Mobilization Complete Looks Like Under This Model

    Under Tier 1: finding resolved, fix deployed, post-fix rescan clean. Three conditions, all automated, documented in the pipeline.

    Under Tier 2: finding resolved, fix deployed, post-fix rescan clean, senior practitioner sign-off recorded against defined criteria. Four conditions. The fourth one is a human judgment, but it’s a specific judgment with a specific scope – not “does this look right” but “have the Tier 2 criteria been met.”

    The difference matters. A defined judgment is auditable. A vague norm isn’t.


    The Staffing Question Nobody Is Asking Yet

    Tier 2 requires senior practitioners with both security depth and code comprehension. That is a specific skill profile. It is not the same as a senior SOC analyst. It is not the same as a senior developer who hasn’t worked in security.

    Most organizations don’t have enough of these people to run Tier 2 verification at scale. That’s not an argument against the model – it’s a reason to be honest about what you can actually run internally versus what requires a different resourcing approach.

    Part 3 of this series covers exactly that question: who owns the second loop, and what does it take to close it reliably?


    This is a three-part series on what CTEM’s mobilization stage gets wrong in an AI-assisted development environment, and what to build instead.

    Part 1: AI proposed your last fix. Did anyone scan it?
    Part 3: Who Closes the Second Loop?

    Read more: CTEM Part 2
  • Closing the Loop in AI Code Fixes

    CTEM Was Built for a Different Problem
    Continuous Threat Exposure Management gave security teams something they badly needed: a systematic way to move from reactive alert-handling to proactive exposure reduction. Scope your environment. Discover what’s exposed. Prioritize by real risk. Validate that risk. Mobilize a fix.
    The framework is sound. But every stage of it was designed with one assumption so obvious nobody wrote it down: a human wrote the remediation.
    When a developer fixed a vulnerability in 2019, a few things were true. They understood the code they were changing – or at least had a working mental model of it. A peer reviewed the diff. The review process was the verification layer. It was imperfect, but it existed, and it was independent of the process that found the vulnerability.
    That independence mattered more than anyone realized.

    What Changes When AI Proposes the Fix

    Your CTEM program is working. Findings are being discovered, prioritized, and closed. Your metrics look clean. Your mobilization rate is up.
    And somewhere in your codebase right now, there is unverified code that your vulnerability management workflow put there.


    Walk through what the current toolchain actually does.
    MDASH – Microsoft’s multi-model agentic scanning engine – finds a vulnerability. It doesn’t rely on pattern matching. It reasons about code logic the way an attacker would, catches what traditional static analysis misses, and produces a finding with full context. So far, this is discovery working better than it ever has.
    Then Security Copilot or GitHub Copilot Autofix proposes a remediation. It analyzes the vulnerability, understands the surrounding code, and rewrites it. The diff appears in the PR. It looks clean. It addresses the finding. Tests pass.
    The developer reviews it. Approves it. Merges it.
    Finding closed.
    But here’s what didn’t happen: nobody scanned the fix.
    The new code that Copilot wrote – the remediation itself – re-entered your codebase as unverified input. It passed a code review, which is a human judgment about whether the logic looks correct. It did not pass the same agentic scanning process that caught the original vulnerability.
    You closed one loop. You opened another. Most CTEM programs have no process for the second one.

    Why This Is Different From “Review Your Code Reviews”


    This is not an argument that code reviews are insufficient, or that developers are careless. Both of those arguments are old and mostly unhelpful.
    This is a structural problem with a specific cause.
    When MDASH finds a vulnerability in AI-generated code, it is often finding something that exists because the original code contained logic that no human fully modeled. That’s the point – it catches what pattern matching misses precisely because human comprehension isn’t the detection mechanism.
    But when Copilot proposes a fix for that vulnerability, the reviewer’s ability to independently verify correctness depends on their comprehension of the original logic. If that logic was generated by AI and never fully understood by a human, the reviewer is evaluating an AI’s answer to a question they never completely understood in the first place.
    The diff looks right. The fix is syntactically correct. The tests pass.
    None of that answers the question: did the fix introduce something new?

    The Recursive Problem


    AI-proposed fixes are code. Code has vulnerabilities. The system that found your original vulnerability did not scan the remediation.
    This is not a theoretical edge case. It is the default state of every AI-assisted remediation workflow that hasn’t explicitly addressed it. Which, right now, is most of them.
    The attack surface for your remediation code is real. A fix that parameterizes an XPath query is easy to reason about – any practitioner can verify it. But as AI-generated code increases as a percentage of your total codebase, and as the vulnerabilities being fixed involve increasingly complex logic, the gap between “syntactically correct fix” and “semantically correct fix” widens.
    Your CTEM program is not built to see that gap. It was designed to close findings, not to treat remediations as new inputs requiring their own discovery cycle.

    The Question Your CTEM Program Can’t Currently Answer


    Go look at your last ten closed findings that were remediated by AI-proposed fixes.
    For each one, ask: was the remediation code scanned before it merged?
    If the answer is no – or if you’re not sure – your mobilization stage has a gap that your metrics aren’t showing you.
    The framework works. The assumption embedded in it doesn’t hold anymore.
    Part 2 of this series covers what fix verification actually requires, and why “have a human review the diff” is not a sufficient control when the code complexity exceeds the reviewer’s mental model.

    What “Mobilization Complete” Needs to Mean Now
    The traditional definition is straightforward: the finding is resolved, the fix is deployed, the ticket is closed.
    That definition needs one additional condition: the remediation has been scanned.
    Not reviewed. Scanned. By the same class of tooling that found the original vulnerability. Because a human code review and an agentic scan are answering different questions. The review asks whether the fix looks correct. The scan asks whether the fix introduced something new.
    You need both answers before you close the loop.
    This is achievable today. MDASH can run as a post-fix gate in your pipeline before PR merge. That’s not a significant workflow change – it’s a pipeline step. But it only happens if you build it in deliberately. It will not happen by default.
    Most teams haven’t built it in. Most teams don’t know they need to.

    Read more: Closing the Loop in AI Code Fixes
  • You named it.

    Persian last names

    Persians didn’t have last names until the 20th century, when in 1925 Reza Shah mandated it. My full last name, Mashhadi Ghadiri, falls into two of the 7 categories of Persian last names. The first part, Mashhadi, refers to someone who has made the pilgrimage to Mashhad, one of the holiest cities in Iran in the Islamic faith, and nods to both power and pilgrimage — Ghadiri comes from ‘Qadir,’ meaning capable. It’s a name about choosing the path with intention.

    Naming cybersecurity incidents

    Cybersecurity incidents are typically named using one of several conventions to aid tracking, communication, and analysis. Common methods include using the date of occurrence (e.g., “Incident-20250425”), the affected entity (e.g., “M365-Incident”), or the threat actor or campaign involved (e.g., “APT29-LateralMove”). Other approaches focus on the attack technique (e.g., “RDP-BruteForce”), the targeted asset (e.g., “ProdAPI-SQLInjection”), the malware or tool used (e.g., “Emotet-Infection”), or a combination of severity and category (e.g., “Critical-DataExfil”). These naming structures help standardize incident reporting and streamline response across teams, but often can make sharing information or understanding similar attacks across entities or organizations.

    So what?

    Both systems are designed to convey identity, origin, and context in a compact, recognizable form. Both systems reflect a deep cultural or operational need: to encode meaning, history, and relationship into something short enough to be remembered—but rich enough to be understood.

    The version you choose to name a cybersecurity incident—just like choosing a surname—shapes how it’s perceived, tracked, and responded to. Here’s why it matters:

    1. Clarity and Communication

    • A well-chosen name instantly signals what happened and to whom.
      • “TokenTheft-SessionHijack” is more actionable than “Incident-0425”.
      • Similarly, Shirazi gives cultural/geographic context in a way Reza alone does not.

    2. Attribution and Analysis

    • Names tied to threat actors (APT29), techniques (RDP-BruteForce), or tools (CobaltStrike) allow teams to connect dots across incidents.
      • Just like Mashhadi tells you someone made pilgrimage to Mashhad, Mimikatz-Use implies credential dumping.

    3. Triage and Prioritization

    • Including severity or asset class in a name helps with prioritization.
      • Critical-DataExfil is clearly urgent.
      • In Persian names, Qadir (capable) implies rank or responsibility, signaling social weight.

    4. Long-Term Tracking and Reporting

    • Incident names become part of historical data and intelligence feeds.
      • Consistent naming enables automation, dashboards, and trend analysis.
      • Attacks follow histories and societal changes across ‘generations’ just the same.

    5. Cultural and Strategic Implications

    • Names reflect what the organization values or fears—whether it’s data loss, nation-state actors, or internal misuse.
      • Just as Persian surnames once signaled social class or religious devotion, incident names can shape an org’s security posture narrative with this incident and future incidents.

    In short: Choosing the right naming convention isn’t just administrative—it’s strategic. It defines how people talk about the threat, understand its origin, and decide what to do next.

    Read more: You named it.
poetry

🔐 Ghazal: “All Access Is Conditional”

(a modern security poem in ghazal form)


In this realm of cloud and claim, all access is conditional
The lover may knock, but still — permission is provisional

The gate is silent, the ID speaks, its posture holds the key
From signal comes salvation — detection is intuitional

Trust no device, no sign-in time, unless the risk aligns
The dance of context and control is wholly intuitional

Her token glowed, yet prompts appeared — a second factor asked
The veil may lift, but only when the bond is traditional

No open ports, no phantom guests, no silent lateral flow
My realm is built on principle, protection constitutional

From Persia’s gardens to Azure clouds, the guardians still remain
Their watchful eyes in every log — the shield is unadditional

And Mona writes, like Hafez would, of XDR and fate
To love the user is to test — the trust must be conditional*

Poetry inspired by a cybersecurity mindset

Exploring the intersection of creativity and security through poetry. Mona reflects on thoughts and lessons that shape her approach.

poetry

© 2025 Mona Ghadiri. All content, including text, images, and original poetry, is the intellectual property of Mona Ghadiri unless otherwise noted. Unauthorized use or reproduction is prohibited.