
LLM de razonamiento especializado para la detección de vulnerabilidades en código fuente en C/C++ y Python, con construcción de conjuntos de datos, entrenamiento SFT/DPO y scripts de reproducción de resultados.
git lfs install # one-time setup
git clone https://github.com/ucsb-mlsec/VulnLLM-R.git
cd VulnLLM-R
# If you cloned before installing Git LFS, run: git lfs pull
conda create -n vulnscan python=3.11
conda activate vulnscan
pip install -e . -e ./vulscan/train/LLaMA-Factory -e ./vulscan/model_zoo
# generate VulnLLM-R-7B's results
python -m vulscan.test.test --output_dir results/test_data --dataset_path ./datasets/test/function_level/ ./datasets/test/repo_level/ --language python c java --model UCSB-SURFI/VulnLLM-R-7B --requests_per_minute 1000 --save --use_cot --batch_size 4 --tp 2 --vllm --max_tokens 8192 --random_cwe
python -m vulscan.test.test_hf \
--output_dir results/test_hf \
--hf_dataset UCSB-SURFI/VulnLLM-R-Test-Data \
--hf_split repo_level function_level \
--language c python java \
--model UCSB-SURFI/VulnLLM-R-7B \
--save --use_cot --vllm --tp 2
# [optional] generate other models' results with our shell script
# remember to add your API keys to .env file if you want to run commercial models
# use ./run_test.sh -h for more options
./vulscan/test/run_test.sh -o results/test_data -t 2 # -o means output directory, -t means tensor parallelism
./vulscan/test/run_test.sh -o results/test_data -M o3-mini # -M means model name, which runs only one model.
./vulscan/test/run_test.sh -o results/test_data -M gpt-5.4 -e high # -e sets reasoning effort (e.g., none/low/medium/high/xhigh)
./vulscan/test/run_test.sh -o results/test_data -M claude-opus-4-6 -e high
# [optional] draw plot to compare with other models
python plots/plot_language_comparison_models.py --results-dir results/test_data
python plots/plot_model_size_scatter.py --results-dir results/test_data # Note: Labels may overlap with scatter points. Adjust text positions manually if needed.
También proporcionamos la versión de razonamiento reducido de los conjuntos de datos destilados:
Fusionar los conjuntos de datos existentes de detección de vulnerabilidades a nivel de función: PrimeVul [1], SecCodePLT [2], Juliet [3], Sven [4], y Arvo [5]. Dentro de estos conjuntos de datos, PrimeVul tiene las funciones más complicadas. Creamos dos conjuntos de entrenamiento: limpio (sin PrimeVul) y ruidoso (con PrimeVul), de modo que podemos entrenar en conjuntos de datos relativamente simples y probar en el complejo conjunto de datos PrimeVul. Tenga en cuenta que llamamos ruidoso al conjunto de entrenamiento con PrimeVul no porque el conjunto de datos sea ruidoso. Es un nombre relativamente arbitrario que usamos al principio.
vulscan/data_process/data_utils contiene un conjunto de scripts para procesar y fusionar los
conjuntos de datos.
raw_to_us.py: Fusionar los datos brutos en nuestro conjunto de datos y eliminar datos redundantescheck_cwe_correct.py: Calcular la precisión para cada categoría de CWEgenerate_arvo_raw_data.py: Generar datos brutos estructurados a partir del conjunto de datos arvoarvo_to_us.py: Reformatear los datos brutos estructurados de arvo al formato de nuestro conjunto de datossplit_good_bad_for_juliet.py: Extraer datos del conjunto de datos Juliet 1.3 original y convertirlos al formato requerido,
que forma parte de nuestro c clean_datasetadd_sven_to_clean_dataset.py: Extraer datos del conjunto de datos Sven, que forma parte de nuestro C clean datasetsync_large_small.py: Sincronizar las modificaciones de noisy_dataset/large_train/c a
noisy_dataset/small_train/cremove_testing_from_training.py: Agregar la etiqueta human a cada dato, lo que significa que el punto ha sido verificado por
humanos y se usa como dato de prueba
-: Agregar el campo related_cwe al conjunto de datos.Después de construir los conjuntos de datos, generaremos datos de razonamiento para nuestro conjunto de entrenamiento.
Consultaremos los modelos de razonamiento DeepSeek-r1 y QwQ para generar los datos de razonamiento y filtraremos los que tengan cadenas de razonamiento muy
largas.
El código para generar datos de razonamiento está en vulscan/data_process/generate_reasoning y los datos de razonamiento se guardarán
en datasets/reasoning_data.
cd vulscan/data_process/generate_reasoning
generate_reasoning/generate.py es el script principal para generar datos de razonamiento.
Para cada punto de datos, generará n muestras de datos de razonamiento y seleccionará la que tenga la respuesta correcta y la longitud más corta.
A continuación se muestran ejemplos de ejecución con los modelos QwQ y DeepSeek-r1 (usando la API de together.AI, que es más lenta pero más estable
que la API oficial):
python generate.py \
--tp 2 \
--dataset_type clean_dataset \
--batch_size 200 \
--n 8 \
--training_set train \
--model_name Qwen/QwQ-32B
# or
python generate.py \
--dataset_type noisy_dataset \
--batch_size 200 \
--n 8 \
--training_set small_train \
--model_name together-deepseek-reasoner \
--together_deepseek
Después de generar los datos de razonamiento brutos, podemos usar otro modelo para resumirlos y hacerlos más cortos sin romper la estructura
python extract_reasoning.py
También podemos filtrar los datos de razonamiento según una longitud determinada con generate_reasoning/filter.py; num_processes se ajusta según el número de núcleos de CPU.
python filter.py \
--dataset_type noisy_dataset \
--training_set small_train \
--model_name Qwen/QwQ-32B \
--filter_input_length 16000 \
--filter_all_length 32000 \
--num_processes 16 \
--filter_correct_only # for filtering wrong predictions
# --model_name together-deepseek-reasoner \
Finalmente, será necesario reformatear los datos de razonamiento generados para el modelo objetivo que entrenaremos (Qwen-Instruct).
python reformat_ds.py \
--dataset_type noisy_dataset \
--training_set small_train \
--model_name Qwen/QwQ-32B \
--filter_input_length 16000 \
--filter_all_length 32000 \
--push_to_hub \
--push_to_hub_organization secmlr \
--filter_correct_only
Para el conjunto de datos DPO:
python generate_dpo.py \
--tp 2 --dataset_type clean_dataset \
--batch_size 200 --n 8 --training_set train \
--model secmlr/VD-QWQ-Clean-8k_qwen2_7B_full_sft_1e-5
consulte vulscan/train/README.md para más detalles
los resultados se guardarán en el directorio results/test_qwen/results.json.
Si desea reproducir nuestros resultados, puede ejecutar el siguiente comando:
# open-source model
python -m vulscan.test.test --output_dir results/one_of_4 \
--dataset_path ./datasets/test/test_clean ./datasets/test/test_primevul_pair \
--language c python --model Qwen/Qwen2.5-7B-Instruct \
--requests_per_minute 100 --save --use_cot \
--use_policy --batch_size 4 --tp 2 --vllm --max_tokens 16384 \
--random_cwe
# api model
python -m vulscan.test.test --output_dir results/one_of_4 \
--dataset_path ./datasets/test/test_clean ./datasets/test/test_primevul_pair \
--language c python --model o3-mini-2025-01-14 \
--requests_per_minute 100 --save --use_cot \
--use_policy --batch_size 4 --max_tokens 16384 --random_cwe
# local saved model
python -m vulscan.test.test --output_dir results/one_of_4 \
--dataset_path ./datasets/test/test_clean ./datasets/test/test_primevul_pair \
--language c python \
--model vulscan/train/result/VD-QWQ-Clean-16k/qwen2_7B_full_sft_1e-5 \
--requests_per_minute 100 --save --use_cot --use_policy \
--batch_size 4 --tp 2 --vllm --max_tokens 16384 --random_cwe
# our model
python -m vulscan.test.test --output_dir results/one_of_4 \
--dataset_path ./datasets/test/test_clean ./datasets/test/test_primevul_pair \
--language c python \
--model secmlr/VD-QWQ-Noisy-Small-8k_qwen2_7B_full_sft_1e-5 --revision aa3235b \
--requests_per_minute 100 --save --use_cot --use_policy \
--batch_size 4 --tp 2 --vllm --max_tokens 16384 \
--random_cwe # whether to randomize the order of cwe and related cwes
Después de las pruebas, las respuestas del modelo y el rendimiento se guardarán en el directorio results/test_data.
Si desea calcular el rendimiento según las respuestas del modelo, puede ejecutar el siguiente comando:
python -m vulscan.test.test_existing_json \
--json_file results/test_data/datasets_test_test_clean__cot_c_policy_QwQ-32B-Preview.json # the results file
python generate_constitution.py --model gpt-4o --input_dir results/train --output_dir results/train/constitution
@article{nie2025vulnllmrspecializedreasoningllm,
title={VulnLLM-R: Specialized Reasoning LLM with Agent Scaffold for Vulnerability Detection},
author={Yuzhou Nie and Hongwei Li and Chengquan Guo and Ruizhe Jiang and Zhun Wang and Bo Li and Dawn Song and Wenbo Guo},
year={2025},
journal={arXiv preprint arXiv:2512.07533},
url={https://arxiv.org/abs/2512.07533},
}
data_utils.pydatasets/clean_dataset: los datos de entrenamiento sin PrimeVul
datasets/clean_dataset/python contiene los datos de SVEN y SecCodePLTdatasets/clean_dataset/c contiene los datos de Juliet y SVENdatasets/noisy_dataset
datasets/noisy_dataset/small_train: Contiene los datos de entrenamiento de PrimeVul y SVEN con CWEs seleccionados (
usamos los datos de PrimeVul en este conjunto como entrenamiento)datasets/noisy_dataset/large_train: Contiene los datos de entrenamiento de PrimeVul, SVEN y SecCodePLT con
más CWEs (este conjunto puede usarse más adelante para entrenar modelos más grandes)datasets/noisy_dataset/test: Un pequeño conjunto de prueba de PrimeVul verificado por humanosdatasets/test
datasets/test/test_clean: Los datos de prueba de SVEN, SecCodePLT y Juliet; con CWEs OOD que no forman
parte del conjunto de entrenamientodatasets/test/test_primevul_pair: Los datos de prueba originales de PrimeVulvulscan/data_process/data_utils/get_cwe_stat.py para obtener el histograma del conjunto de datos| Dataset | Lenguaje | Entren./prueba | CWE | # Benignos | # Vulner. | Longitud promedio |
|---|
| Clean (seccodeplt) | Python | Entrenamiento | 20 | 1281 | 1281 | 741 |
| Clean (juliet) | C/C++ | Entrenamiento | 22 | 1716 | 1653 | 3689 |
| Hard (primevul filtered) | C/C++ | Entrenamiento | 26 | 2717 | 2952 | 4689 |
| Long Context (Oss-fuzz) | C/C++ | Entrenamiento | 3 | 475 | 604 | 12761 |
| Simple (seccodeplt) | Python | Prueba | 24 (6 ood) | 74 | 74 | 814 |
| Simple (juliet) | C/C++ | Prueba | 38 (14 ood) | 358 | 376 | 2575 |
| Hard (PrimeVul, SecLLMHolmes) | C/C++ | Prueba | 13 (5 ood) | 145 | 152 | 4545 |
| Long Context (Oss-fuzz) | C/C++ | Prueba | 3 (0 ood) | 0 | 320 | 18929 |
| primevul test (noisy) | C/C++ | Prueba | 56 (34 ood) | 421 | 422 | 5341 |