As both a software engineer and an ML researcher, I use code-generating language models daily—and I see firsthand how optimizing purely for pass@1 on functional unit tests creates a dangerous blind spot. On benchmarks like SecurityEval and CyberSecEval, state-of-the-art code models generate exploitable vulnerabilities (such as SQL string interpolation CWE-89, OS command injection CWE-78, or weak cryptographic modes CWE-327) in \(25\text{–}40\%\) of security-sensitive prompts! Worse, when an agentic coding loop is asked to fix a static-analyzer warning on an unfamiliar framework, it frequently "hacks around" the rule (e.g., obfuscating the taint flow or hallucinating a non-existent sanitizer function) rather than admitting uncertainty. This research topic introduces Verification-Guided Block Decoding with Risk-Aware Abstention, coupling statement-level AST/dataflow verification during generation with a calibrated selective abstention gate when neither candidate trajectory can discharge both security and functional constraints.
Excellent fit with my full-stack software engineering experience and builds a distinctive research identity in reliable AI-assisted programming. Integrating formal static/AST verifiers into token/block decoding requires careful engineering across language parsers.
Current code generation benchmarks (HumanEval, MBPP, SWE-bench) evaluate functional correctness (pass@k) while ignoring security vulnerabilities (e.g., SQL injection CWE-89, path traversal CWE-22, unsafe deserialization CWE-502). Existing post-hoc repair agents run static analyzers only after generating the full program—and when the model lacks knowledge of a secure library API, iterative self-repair loops often silence the linter warning by breaking functionality or introducing a deeper logic flaw instead of abstaining.
Basic Information
| Field | Details |
|---|---|
| Core Focus | Top AI-for-Software-Engineering & Safety Topic |
| Final Research Title | Formal Verification-Guided Decoding and Risk-Aware Abstention in Agentic Language Models for Secure Code Generation |
| Working Title | Safe-by-Construction Statement Decoding and Calibrated Abstention for Code LLMs |
| Research Area | AI for Software Engineering (AI4SE), LLM Agents & Reliable ML |
| Subfield | Secure Code Generation, Neuro-Symbolic Verification & Selective Prediction |
| Target Academic Level | MSc Thesis / PhD Track |
| Current Status | Scoped for Python & Web/Systems Security (CWE Top 25) |
Idea Summary
2.1 One-Sentence Core Thesis
Guide code LLM generation at AST statement boundaries using lightweight incremental static/taint verifiers (Tree-sitter + dataflow rules) and enforce a calibrated security-abstention policy that refuses to emit unverified code when token-level epistemic uncertainty and static taint risk cannot be resolved within \(B\) search branches.
2.2 Research Motivation & Strategic Fit
- Unique Personal Fit: Unlike pure ML candidates who only know image classification, my production software engineering experience with web backends, databases, and security gives me a major advantage in designing realistic AST/taint verifiers.
- Why #10: Formal verification on arbitrary general-purpose code is undecidable in the general case; keeping the scope tight requires focusing on incremental AST + intraprocedural taint/API contract verification in Python/JavaScript across the MITRE Top-25 CWEs.
Problem Exploration & Identified Research Gap
3.1 Why Post-Hoc Linter Repair Loops Fail
Current agentic coding workflows generate a complete function \(y\), run a static analyzer (Bandit, Semgrep, or CodeQL), and feed the warning back into the LLM prompt. In practice, this exhibits two critical failure modes:
- 1Reward Hacking / Warning Suppression: To make the static warning disappear, the LLM often deletes the required feature, catches and silences exceptions (
except Exception: pass), or wraps untrusted input in a no-op helper that fools simple regex linters without actually sanitizing the payload. - 2Hallucinated Security APIs Under Epistemic Ignorance: When prompted with a niche library or cryptographic requirement outside its confident knowledge, the LLM guesses plausible-looking parameter flags (e.g.,
verify=Falseor deprecated cipher modes) with high token probability.
3.2 Explicit Research Gap
Recent secure-coding work focuses either on training-time preference tuning (SafeCoder, He et al., ICSE/CCS 2024) or unconstrained post-hoc agent reflection. Meanwhile, constrained decoding methods (SynCode, Ugare et al., 2024) only enforce syntactic grammar (context-free grammars), not semantic security invariants (taint flow from untrusted sources to sinks), and none incorporate formal selective abstention (\(\perp\)) when a secure, functionally valid implementation is outside the model's verified capability.
Proposed Research Direction
4.1 Mathematical & Algorithmic Formulation: Statement-Level Verifier-Guided MCTS/Beam Decoding
Let a partial program consist of AST statements \(S_{1:t} = (s_1, \dots, s_t)\). At statement step \(t+1\), the Code LLM proposes \(K\) candidate next statements \(\{s_{t+1}^{(1)}, \dots, s_{t+1}^{(K)}\}\). For each candidate prefix \(S_{1:t} \oplus s_{t+1}^{(k)}\), an incremental verifier \(\mathcal{V}_{\text{sec}}\) evaluates:
- 1API & Hallucination Check (\(\mathcal{V}_{\text{sym}} \in \{0, 1\}\)): Verifies that imported symbols and security-critical kwargs exist in the target environment's type stubs.
- 2Incremental Taint & CWE Invariant (\(\mathcal{V}_{\text{taint}} \in [0, 1]\)): Tracks untrusted input variables \(\mathcal{T}_{\text{source}}\) and prunes any branch where a tainted variable reaches a sensitive sink (
cursor.execute,subprocess.run,open,eval,render_template_string) without passing through a allowlisted sanitizer or parameterized binding.
Each surviving complete program \(Y\) is scored by its joint Functional-and-Security Confidence:
If \(\max_{k \in \{1..B\}} \kappa_{\text{sec}}(Y^{(k)} \mid x) < \tau_{\alpha}\) (calibrated via Conformal Risk Control on a validation split), the agent abstains from emitting executable code and instead outputs a structured Security Deferral Report highlighting the unresolved CWE sink for the human developer.
flowchart LR
P["Coding Prompt x"] --> GEN["Code LLM Statement Proposer<br/>K Candidate AST Statements"]
GEN --> VER["Incremental AST & Taint Verifier<br/>(Prunes CWE Sinks & Hallucinated APIs)"]
VER -- "Valid Safe Branches" --> NEXT["Continue Decoding / Run Sandbox Tests"]
NEXT --> GATE{"Risk-Aware Abstention Gate<br/>max_k κ_sec(Y^(k)) ≥ τ_α ?"}
GATE -- "Verified Safe & Functional" --> EMIT["Emit Verified Code Y*"]
GATE -- "All Branches Violate CWE or Low Conf" --> ABST["Abstain (⊥) + Emit CWE Diagnostic<br/>Zero Vulnerable Code Emitted"]Preliminary Technical Plan
- Code Models:
Qwen2.5-Coder-7B-InstructandDeepSeek-Coder-6.7B-Instruct. - Benchmarks:
- 1SecurityEval & Purple Llama CyberSecEval: Measuring Vulnerable Code Rate (\(\text{VCR}\downarrow\)).
- 2SafeCoder Joint Benchmark (HumanEval/MBPP + CWE Security): Measuring joint functional + secure accuracy (
pass_sec@1).
- Baselines: Greedy/Nucleus Decoding, Self-Debugging / Post-Hoc Bandit Repair Loop (\(3\) iterations), System-Prompt Security Instruction, and SafeCoder SFT.
- Metrics:
pass@1(functional),sec_pass@1(both functional AND zero CWE vulnerabilities), Selective Vulnerability Escape Rate at \(80\% / 90\%\) coverage, and AURC.
Expected Contributions
- 1Statement-Level Taint-Guided Decoding: Prunes insecure CWE trajectories during generation rather than hoping post-hoc self-repair won't break the code.
- 2Risk-Bounded Secure Code Abstention: Introduces the first selective prediction / conformal abstention framework for secure code generation, reducing vulnerable code escapes toward \(0\%\) on supported CWE classes.
Feasibility, Scope, and Honest Risks
- Feasibility: Focused strictly on Python (using Python's built-in
astmodule +Tree-sitter+ custom lightweight taint rules for Top-10 Python CWEs: SQLi, Command Injection, Path Traversal, Deserialization, Hardcoded Secrets, Weak Crypto, SSRF, XSS). Incremental AST parsing in Python takes \(< 0.5\text{ ms}\) per statement! - Main Risk & Mitigation: Over-abstaining on benign code that uses dynamic Python features. Mitigation: Use the abstention mode to present the top candidate inside a commented warning block with the exact tainted line highlighted, measuring the exact Risk-Coverage trade-off curve.
Initial Literature Notes
- [1]J. He and M. Vechev, "Large Language Models for Code: Security Hardening and Adversarial Testing (SafeCoder)," ACM CCS / ICSE, 2023/2024.
- [2]H. Pearce et al., "Asleep at the Keyboard? Assessing the Security of GitHub Copilot's Code Contributions," IEEE S&P, 2022.
- [3]S. Ugare et al., "SynCode: LLM Generation with Grammar Augmentation," arXiv:2403.01632, 2024.
- [4]M. Bhatt et al., "Purple Llama CyberSecEval: A Secure Coding Benchmark for Language Models," Meta AI, 2023/2024.
Idea Validation Checklist
- Verified
- Verified
- Verified
- Pending
Current Assessment
| Criterion | Score | My Assessment Notes |
|---|---|---|
| Problem clarity | 9 / 10 | Vulnerable AI-generated code is a massive industry problem. |
| Novelty potential | 9 / 10 | Combining incremental taint-guided decoding with selective abstention is novel. |
| Technical feasibility | 8 / 10 | Requires solid Python AST engineering (a strong suit for me). |
| Resource feasibility | 9 / 10 | Qwen2.5-Coder-7B runs fast on 1x 24GB GPU. |
| Dataset availability | 9 / 10 | SecurityEval and CyberSecEval are open-source. |
| Publication potential | 9 / 10 | Top fit for ICSE, FSE, ASE, ISSTA, or NeurIPS/ICLR LLM tracks. |
| Personal interest | 10 / 10 | Combines my two identities: Software Engineer + AI Reliability Researcher. |
Next Actions
- 1Run baseline
Qwen2.5-Coder-7B-Instructon the 121 prompts ofSecurityEvaland categorize every generated CWE vulnerability. - 2Prototype the statement-level AST taint filter for
CWE-89,CWE-78, andCWE-22.
Open Questions and Working Notes
- How often does pruning an insecure statement branch (e.g.,
f"SELECT * FROM users WHERE name = '{user}'") at temperature \(T=0.2\) cause the model's very next branch to naturally switch to parameterized queries (cursor.execute("... WHERE name = ?", (user,))) without any fine-tuning?