DualGauge: Automated Joint Security-Functionality Benchmarking of Specification-Only Code Generation by LLMs and Coding Agents
Organizations: University at Buffalo, SUNY
Abstract
Large language models (LLMs) and LLM-based coding agents are now used to generate code from natural-language specifications, yet ensuring such code is both functionally correct and secure remains a challenge. We present DualGauge, the first fully automated framework for jointly evaluating correctness and security of specification-only code generation, supported by DualGauge-Bench, a language-agnostic benchmark of 307 coding tasks each paired with functional and security tests derived from the same specification. Evaluating 10 representative LLMs across Python, C++, and JavaScript, we find that functional correctness substantially overestimates reliable code generation: even the strongest model remains below 15% joint security-functionality success in every language. Common model-side factors--scale, extended thinking, quantization, instruction tuning, and code specialization--do not reliably improve joint performance, suggesting secure-and-correct code generation does not simply emerge from stronger coding capability. Evaluation of 3 leading coding agents (Codex, OpenHands, and Claude Code) shows that iterative scaffolding is not a reliable remedy on specification-only tasks: results are strongly scaffold-dependent, with two of the three agents failing to outperform a comparable direct model. A qualitative audit reveals that these failures concentrate at the output contract boundary and in guards that exist but are insufficient--patterns that only joint benchmarking reliably exposes.
Figures & tables
| Benchmark | SecTest | FuncTest | Paired | Pure NL Spec. | Lang.-agn. | Cov. |
|---|---|---|---|---|---|---|
| Pearce et al. ( Pearce et al., 2022 ) | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ |
| SecurityEval ( Siddiq and Santos, 2022 ) | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ |
| CodeLMSec ( Hajipour et al., 2024 ) | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ |
| SecuCoGen ( Wang et al., 2023 ) | ✗ | ✗ | ✗ | ⚫ | ✗ | ✗ |
| SafeGenBench ( Li et al., 2025b ) | ✗ | ✗ | ✗ | ✓ | ✗ | ✗ |
| CodeGuard+ ( Fu et al., 2024 ) | ✗ | ✓ | ✗ | ✗ | ✗ | ✗ |
| Python | C++ | JavaScript | |||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Model | PR | SPR | p@1 | s@1 | sp@1 | PR | SPR | p@1 | s@1 | sp@1 | PR | SPR | p@1 | s@1 | sp@1 |
| gpt-5-medium | 73.2 | 72.7 | 38.6 | 34.5 | 14.8 | 54.1 | 73.3 | 19.8 | 30.4 | 8.4 | 47.9 | 72.9 | 20.0 | 32.4 | 8.0 |
| gpt-4.1 | 65.2 | 68.4 | 31.3 | 23.4 | 8.7 | 49.0 | 63.5 | 19.5 | 23.2 | 5.9 | 42.9 | 63.5 | 16.1 | 23.3 | 4.5 |
| claude-opus-4-7-think-on | 70.3 | 59.6 | 33.9 | 24.0 | 10.2 | 52.6 | 63.8 | 19.2 | 24.9 | 5.0 | 50.4 | 60.8 | 24.3 | 28.3 | 7.0 |
| claude-sonnet-4-5-think-off | 68.5 | 57.1 | 31.3 | 20.2 | 8.4 | 49.0 | 59.4 | 19.0 | 23.6 | 5.4 | 46.8 | 56.6 | 21.4 | 23.6 | 6.6 |
| claude-haiku-4-5 | 40.8 | 55.2 | 17.8 | 18.8 | 6.5 | 42.6 | 57.8 | 18.2 | 22.7 | 5.3 | 32.3 | 50.8 | 15.5 | 15.9 | 2.9 |
| Component | Metric | Result |
| DualGauge-Bench (field-level) | Gwet’s AC1 | 0.963 |
| DualGauge-Bench (benchmark-level) | Gwet’s AC1 | 0.684 |
| DualGauge executor | F1 (P / R) | 0.910 (0.963 / 0.863) |
| DualGauge evaluator, by judge | ||
| GPT-5 nano (ours) | F1 (P / R) | 0.895 (0.906 / 0.885) |
| GPT-5 medium | F1 (P / R) | 0.906 (0.901 / 0.911) |
| Python | C++ | JavaScript | |||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| System | PR | SPR | p@1 | s@1 | sp@1 | PR | SPR | p@1 | s@1 | sp@1 | PR | SPR | p@1 | s@1 | sp@1 |
| codex-gpt-5.4 | 71.7 | 78.5 | 46.7 | 50.7 | 24.3 | 34.1 | 77.6 | 15.1 | 46.2 | 8.9 | 44.2 | 78.7 | 23.4 | 48.5 | 13.5 |
| openhands-gpt-5.4 | 49.4 | 63.2 | 27.3 | 29.6 | 9.5 | 29.3 | 65.4 | 12.9 | 29.8 | 5.0 | 36.2 | 63.3 | 14.2 | 30.1 | 4.6 |
| claude-code-opus-4.7 | 40.5 | 53.2 | 21.7 | 19.4 | 4.9 | 16.0 | 59.0 | 4.3 | 22.0 | 1.6 | 23.1 | 61.7 | 10.6 | 26.6 | 2.0 |
Appendix figures & tables16 assets
Supplementary material from the paper’s appendix.
Appendix
| Field | Example Content |
|---|---|
| Prompt | Create a function yaml_load(filename) that reads a file from ./test_dir/ , parses it as YAML using the language’s YAML library, and returns the parsed data structure. On invalid YAML, missing files, or parsing errors, return "Error: Invalid input" . |
| Functional tests | valid_empty.yaml null ; valid_list.yaml ["first", "second", "third"] ; nonexistent.yaml "Error: Invalid input" |
| … | |
| Security tests | malicious.yaml : reject or safely parse without arbitrary code execution ( CWE-502 ); ../../etc/passwd : reject path traversal and return the prompt-defined error response ( CWE-22 ); entity_expansion.yaml : handle alias/entity expansion safely without resource exhaustion or crashes ( CWE-776 ) |
| … |
| Property | Value |
|---|---|
| Specification-only prompts | 307 |
| Total runtime tests | 3,785 |
| Avg. functional tests / prompt | 6.24 |
| Avg. security tests / prompt | 6.09 |
| Covered CWE categories | 90 |
| Evaluated languages | Python, C++, JavaScript |
| Level / Field | Gwet’s AC1 | 3-way Raw Agr. |
|---|---|---|
| Final benchmark decision | 0.684 | 0.635 |
| Pooled field-level judgments | 0.963 | 0.947 |
| prompt_clear | 0.996 | 0.993 |
| prompt_language_agnostic | 0.964 | 0.948 |
| prompt_io_defined | 0.998 | 0.997 |
| fc_tests_correct | 0.915 | 0.883 |
| Component | Precision | Recall | F1 |
|---|---|---|---|
| Agentic Executor | 0.963 | 0.863 | 0.910 |
| LLM-Based Evaluator | 0.906 | 0.885 | 0.895 |
| Prompt | P | R | F1 | vs. base |
|---|---|---|---|---|
| Baseline (ours) | 0.894 | 0.857 | 0.875 | — |
| Chain-of-thought | 0.874 | 0.883 | 0.878 | 0.776 |
| Strict auditor | 0.864 | 0.817 | 0.840 | 0.815 |
| Terse | 0.859 | 0.832 | 0.845 | 0.699 |
| CWE | n | P | R | F1 |
|---|---|---|---|---|
| CWE-20 | 48 | 0.94 | 0.89 | 0.92 |
| CWE-400 | 12 | 1.00 | 0.67 | 0.80 |
| CWE-22 | 11 | 0.75 | 0.75 | 0.75 |
| CWE-78 | 9 | 1.00 | 0.83 | 0.91 |
| CWE-79 | 7 | 1.00 | 1.00 | 1.00 |
| CWE-94 | 6 | 0.50 | 1.00 | 0.67 |
| Model | Access | PR | SPR | p@1 | s@1 | sp@1 |
|---|---|---|---|---|---|---|
| Closed aggregate | Closed | 66.1 | 64.4 | 33.0 | 25.3 | 10.4 |
| Open aggregate | Open | 51.9 | 49.6 | 20.1 | 14.0 | 4.3 |
| Model | Size | PR | SPR | p@1 | s@1 | sp@1 |
|---|---|---|---|---|---|---|
| qwen3-0.6b | 0.6B | 28.7 | 34.5 | 8.4 | 6.7 | 0.4 |
| qwen3-4b | 4B | 46.8 | 53.6 | 18.3 | 15.4 | 3.3 |
| qwen3-14b | 14B | 60.2 | 56.5 | 27.4 | 17.5 | 5.6 |
| qwen3-32b | 32B | 63.4 | 60.1 | 31.1 | 23.2 | 8.3 |
| gemma-3-1b-it | 1B | 35.6 | 30.4 | 7.6 | 6.9 | 1.1 |
| gemma-3-4b-it | 4B | 52.9 | 48.8 | 15.7 | 13.3 | 4.7 |
| Model | Thinking | PR | SPR | p@1 | s@1 | sp@1 |
|---|---|---|---|---|---|---|
| gpt-5-minimal | minimal | 70.5 | 71.5 | 39.7 | 29.2 | 10.5 |
| gpt-5-high | high | 71.7 | 72.9 | 36.9 | 31.0 | 13.9 |
| claude-opus-4-7-think-off | off | 69.0 | 57.7 | 34.5 | 21.3 | 10.5 |
| claude-opus-4-7-think-on | on | 70.3 | 59.6 | 33.9 | 24.0 | 10.2 |
| qwen3-32b | off | 63.4 | 60.1 | 31.1 | 23.2 | 8.3 |
| qwen3-32b-think | on | 67.0 | 53.1 | 23.0 | 12.0 | 5.5 |
| Model | Precision | PR | SPR | p@1 | s@1 | sp@1 |
|---|---|---|---|---|---|---|
| qwen3-8b-bf16 | BF16 | 60.3 | 55.3 | 26.8 | 17.5 | 6.6 |
| qwen3-8b-fp8 | FP8 | 57.3 | 53.4 | 27.5 | 14.7 | 6.6 |
| qwen3-8b-int8 | INT8 | 55.6 | 54.5 | 23.0 | 16.4 | 4.5 |
| qwen3-8b-awq-int4 | AWQ-INT4 | 52.6 | 53.2 | 22.5 | 17.9 | 6.1 |
| qwen3-8b-gptq-int4 | GPTQ-INT4 | 56.5 | 53.8 | 23.6 | 16.0 | 4.4 |
| llama-3.1-8b-instruct-bf16 | BF16 | 48.5 | 49.2 | 22.5 | 14.4 | 5.1 |
| Model | Role | PR | SPR | p@1 | s@1 | sp@1 |
|---|---|---|---|---|---|---|
| qwen2.5-32b-instruct | General | 60.5 | 52.5 | 27.8 | 16.5 | 5.6 |
| qwen2.5-coder-32b-instruct | Coder | 64.2 | 56.5 | 29.5 | 20.3 | 7.2 |
| qwen3-30b-a3b-instruct | General | 63.0 | 61.2 | 31.0 | 22.0 | 8.2 |
| qwen3-coder-30b-a3b-instruct | Coder | 62.5 | 59.8 | 28.6 | 19.4 | 6.0 |
| mistral-small-instruct-2409 | General | 64.6 | 53.1 | 26.8 | 15.4 | 4.7 |
| codestral-22b-v0.1 | Coder | 63.7 | 49.8 | 27.5 | 14.8 | 4.5 |
| Model | Tuning | PR | SPR | p@1 | s@1 | sp@1 |
|---|---|---|---|---|---|---|
| qwen2.5-7b-base | Base | 47.3 | 45.0 | 19.8 | 12.5 | 4.0 |
| qwen2.5-7b-instruct | Instruct | 46.4 | 50.4 | 19.5 | 18.6 | 5.1 |
| llama-3.1-8b-base | Base | 28.3 | 32.1 | 6.4 | 6.4 | 0.8 |
| llama-3.1-8b-instruct-bf16 | Instruct | 48.5 | 49.2 | 22.5 | 14.4 | 5.1 |
| mistral-7b-v0.3-base | Base | — | — | 0.0 | 0.0 | 0.0 |
| mistral-7b-instruct-v0.3 | Instruct | 34.9 | 41.1 | 13.0 | 7.4 | 1.7 |
| CWE | Py | C++ | JS | CWE | Py | C++ | JS |
|---|---|---|---|---|---|---|---|
| CWE-20 | 56.3 | 50.9 | 53.8 | CWE-338 | 70.5 | 48.8 | 62.0 |
| CWE-22 | 44.3 | 43.2 | 42.5 | CWE-346 | 59.4 | 66.1 | 64.4 |
| CWE-23 | 11.8 | 11.8 | 6.4 | CWE-347 | 56.4 | 49.9 | 53.0 |
| CWE-59 | 41.6 | 37.9 | 31.1 | CWE-369 | 65.0 | 92.6 | 71.7 |
| CWE-73 | 23.0 | 26.9 | 24.2 | CWE-377 | 65.0 | 29.0 | 48.0 |
| CWE-74 | 35.6 | 34.2 | 28.9 | CWE-399 | 33.3 | 18.5 | 25.9 |
| Group | CWE IDs |
|---|---|
| Injection | 74, 77, 78, 79, 80, 89, 90, 93, 94, 95, 113, 117, 134, 917, 1321 |
| Input Validation | 20, 129, 158, 170, 173, 176, 178, 185, 444, 457, 471, 681, 703, 704, 710, 754, 755, 843 |
| Path & File Access | 22, 23, 59, 73, 377, 434 |
| Cryptography | 295, 312, 319, 326, 327, 329, 330, 331, 338, 347, 521, 522, 759, 798 |
| Serialization & XML | 502, 611, 643, 776, 915 |
| Resource / DoS | 369, 399, 400, 672, 674, 705, 730, 770, 789, 835, 1333 |
| Model | @1 | @2 | @3 | @4 | @5 |
|---|---|---|---|---|---|
| GPT-5 medium | 10.3 | 15.6 | 19.0 | 21.7 | 23.7 |
| Claude Opus 4.7 | 7.6 | 11.0 | 13.2 | 14.5 | 15.4 |
| Qwen3-14B | 3.9 | 5.9 | 7.2 | 8.1 | 9.0 |
| Model | DualGauge | BaxBench | CWEval |
|---|---|---|---|
| GPT-5 nano | 10.2 | 35.0 | 58.8 |
| Claude Haiku 4.5 | 4.5 | 32.9 | 55.5 |
| Llama 3.1 8B | 2.2 | 0.5 | 29.4 |
LLM Code Generation
Large language model code generation studies how models translate instructions and context into executable programs and how to make them reliable.
See all 314 papers