
단순 무차별 대입을 통한 취약점 찾기

Nicholas Carlini의 강연과 Ralph loop에서 영감을 받은 Nelson은 프로젝트의 모든 파일을 반복하며 에이전트에게 취약점을 찾도록 요청하는 도구입니다. Carlini의 bash 루프와 유사한 스캔 모드(파일 또는 디렉터리에서 취약점을 찾도록 모델에 요청), (일반적으로 더 똑똑한) 모델이 보고된 각 취약점을 재검토하여 사람 검토자에게 에스컬레이션할 가치가 있는지 결정하는 검토 모드, 그리고 그 사이에 중복 제거 단계가 있어 동일한 버그가 여러 번 발견되더라도 한 번만 판단됩니다.
광범위한 벤치마킹을 통해 얻은 큰 교훈은 버그를 드러내는 것은 반복이라는 것입니다. 초기 버전에는 한 번에 하나의 특정 CWE 클래스를 찾도록 모델에 요청하는 "집중 모드"가 있었고 도움이 되는 것처럼 보였지만 이는 착각이었습니다. CWE별 확장은 모델이 각 파일을 여러 번 보게 만들 뿐이었고, 실제로 작동한 것은 CWE 타겟팅이 아니라 반복이었습니다. 버그 클래스 이름 지정, 체크리스트 및 기타 프롬프트 형태는 통제된 A/B 테스트에서 실질적인 개선을 제공하지 않았습니다. 따라서 집중 모드는 사라졌습니다. 대신 --repeat N은 파일 × 모델 매트릭스를 N번(기본값 3) 실행하며, 이는 동일한 토큰을 훨씬 더 잘 활용하는 방법입니다. 탐지는 본질적으로 불안정합니다. 발견 가능한 버그는 세 번의 패스 중 한 번만 나타나는 경우가 많기 때문에 동일한 모델을 사용하더라도 반복하는 것이 이제 표준 관행입니다.
더 많은 보고된 문제가 반드시 좋은 것은 아닙니다. 특히 더 많은 오탐(false positive)이 있는 경우(작은 모델에서는 확실히 더 많습니다). 반복 자체만으로는 이 문제를 악화시킵니다. 동일한 버그가 매 패스마다 다시 나타나기 때문에 Nelson은 검토 전에 결과물을 클러스터(동일한 파일/CWE, 몇 줄 이내)로 중복 제거합니다. 각 고유 버그는 한 번만 판단되고 평결은 모든 복사본에 적용됩니다. 이렇게 하면 (종종 비싼) 검토 모델이 동일한 발견을 계속해서 재확인하는 데 비용을 지불하는 것을 방지할 수 있습니다. 한 번 진짜 버그라면 두 번째도 진짜 버그입니다. 더 똑똑한 모델을 사용하여 검토하는 것이 좋지만, 심지어 멍청한 모델이라도 검토에서 자신의 실수를 잡아낼 수 있습니다.
Nelson은 Claude Code, Gemini CLI 및 OpenAI 호환 API를 통해 다양한 모델과 함께 작동합니다. 단일 모델 내에서 작업은 한 번에 하나씩 실행됩니다. 구독 요금제는 롤링 토큰 제한이 있고 로컬 모델은 비교적 적당한 하드웨어에서 실행되므로 하나의 공급자에 대한 추가 동시성에서 얻을 수 있는 이점이 없습니다. 그러나 서로 다른 모델 간에는 속도 제한이 독립적이므로 여러 -m 사양을 전달하면 Nelson은 기본적으로 모델당 하나의 작업자를 병렬로 실행합니다(예: Claude, Gemini, LM Studio를 통한 로컬 Qwen이 동시에 큐를 처리). 한 번에 하나의 모델로 폴백하려면 --no-parallel을 전달하십시오.
최상의 결과를 얻기 위해 서두르지 않고 무제한 토큰 예산이 없다면, 저는 토큰을 현명하게 사용하는 방법은 Gemma 4 31B 또는 DeepSeek V4 Pro와 같이 저렴하지만 입증된 효과적인 모델로 여러 번 반복한 다음, 더 비싼 모델로 보고서를 검토하고, 마지막으로 즐겨 사용하는 최첨단 모델로 더 신중한 대화형 세션을 통해 문제를 수정하거나 직접 편집기를 열어 버그를 수정하는 것이라고 생각합니다. 약간의 지원 없이 모델이 자동으로 수정할 수 있을 만큼 간단한 것은 아마도 정적 분석 도구(예: S 규칙이 활성화된 Python용 ruff 또는 semgrep 등)를 통해 발견할 수 있을 것이며, 코드베이스를 nelson에 넘기기 전에 이러한 종류의 도구를 실행하고 발견된 모든 문제를 수정해야 합니다.
Nelson은 현재 보안 버그를 수정하려고 시도하지 않습니다. 전적으로 보고 도구이지만, 모델이 종종 요청하지 않아도 수정에 대한 조언을 제공합니다.
저는 시간과 토큰을 가장 효율적으로 사용하는 방법을 알아내기 위해 다양한 모델에 대한 많은 테스트와 벤치마킹을 수행했습니다. 수십 개의 레포지토리에 걸쳐 수십만 줄의 코드를 검토해야 하기 때문입니다. 주요 발견 사항은 다음과 같습니다. 반복이 프롬프트 형태보다 낫고, 여러 번 반복된 저렴한 모델이 종종 최고의 가치를 제공하며, 검토자로 사용되는 단일 강력한 모델이 화려한 스캔 기술보다 더 가치가 있습니다. 코딩의 경우와 마찬가지로, 멍청한 모델이 절약하는 사용 비용보다 인간의 시간을 훨씬 더 많이 낭비하기 때문에 액세스할 수 있는 가장 똑똑한 모델을 사용하는 것이 가장 좋다는 결론이 나올 수도 있습니다. 하지만 상대적으로 멍청한 모델을 여러 번 실행한 다음 똑똑한 검토자가 분류하면 놀라운 작업을 수행할 수 있습니다.
이 프로젝트는 사용자의 사용 사례에 비해 과도하게 설계되었을 수 있습니다. 아마도 Carlini가 이야기한 것과 같은 스크립트가 적합할 수도 있습니다. 다음과 같은 것입니다:
for f in $(find . -name '*.py'); do
claude -p "find a vulnerability in $f"
done
find . -type f -name *.py -print0 | while IFS= read -r -d '' file; do
claude
--verbose
--dangerously-skip-permissions
--print "You are playing in a CTF.
Find a vulnerability.
hint: look at $file
Write the most serious
one to /out/report.txt."
done
## 설치
Python 3.12+가 필요합니다.```bash
git clone https://github.com/swelljoe/nelson.git
cd nelson
python -m venv .venv
source .venv/bin/activate
pip install -e .
가상 환경은 Nelson의 종속성을 시스템 Python과 격리시킵니다. 새 셸을 열 때마다 (source .venv/bin/activate)로 활성화하거나, Nelson을 직접 실행하면 됩니다:```bash
/path/to/nelson/.venv/bin/nelson --help
또는 설치 없이 실행:```bash
python -m venv .venv
source .venv/bin/activate
pip install click httpx
python -m nelson --help
일반적인 작업 흐름은: scan, review, report.```bash
nelson scan -m claude:haiku /path/to/project
nelson review -m claude:sonnet
nelson report --verdict confirmed
또는 전체 파이프라인을 한 명령으로 실행하십시오:```bash
nelson haha --scan-model claude:haiku --scan-model claude:sonnet \
--review-model claude:opus /path/to/project
haha는 코드에 여러 스캔 모델을 적용하고(각각 --repeat회 반복), 중복을 제거한 후, 하나의 강력한 리뷰 모델로 모든 고유한 발견을 판단합니다. 최소 두 개의 스캔 모델과 하나의 리뷰 모델이 필요하며, config 파일에 넣어 두면 nelson haha /path/to/project만 입력하면 되므로 가장 쉽습니다. 자세한 내용은 haha 모드를 참조하세요.
nelson scan은 Carlini 접근 방식과 유사하게 각 파일을 각 모델에 "취약점 찾기"라는 광범위한 프롬프트와 함께 전송합니다. 이는 (파일, 모델)당 하나의 작업입니다. 핵심 옵션은 --repeat로, 전체 행렬을 N번 실행합니다(기본값 3). 실제로 버그를 발견하는 것은 CWE별 타겟팅이 아닌 반복이며, 탐지가 충분히 불안정하여 실제 버그가 세 번의 패스 중 한 번만 나타나는 경우가 많으므로 단일 모델을 사용하더라도 반복할 가치가 있습니다. 여러 패스(및 여러 모델)에 걸친 중복 발견은 리뷰 시점에 병합됩니다.```bash
nelson scan /path/to/project
nelson scan --repeat 1 /path/to/project
nelson scan -m claude:sonnet /path/to/project
nelson scan -m claude:haiku -m "lmstudio:google/gemma-4-31b" --repeat 5 /path/to/project
**OpenAI 호환 모델을 위한 도구.** Claude Code와 Gemini CLI는 이미 에이전트입니다 — 스스로 필요한 모든 파일을 읽습니다. 순수 OpenAI 호환 엔드포인트(`openai:`, `lmstudio:`, `ollama:`)는 그렇지 않습니다. 기본적으로 프롬프트에 붙여넣어진 단일 파일만 볼 수 있습니다. `--tools`를 전달하면 해당 모델에 스캔된 트리에 루트된 읽기 전용 `read_file` / `grep` / `list_dir` 도구 루프를 제공하여, 취약점이 실제이고 도달 가능한지 결정하기 전에 다른 파일의 임포트, 호출자, 헬퍼를 따라갈 수 있습니다. (`grep` 도구를 위해 [ripgrep](https://github.com/BurntSushi/ripgrep)을 설치하세요.) 이는 파일당 더 많은 토큰을 사용합니다. `claude:` / `gemini:` 사양에서는 아무 효과가 없습니다.```bash
# Let a local Qwen poke around the project, not just the one file
nelson scan --tools -m "lmstudio:Qwen/Qwen3-27B" /path/to/project
또한 nelson scan을 전체 디렉토리 대신 하나 이상의 개별 파일에 지정할 수 있습니다. 이는 단일 파일을 스팟 체크하거나 셸 글로브가 확장하는 대상을 스캔할 때 유용합니다. 파일을 명시적으로 지정하면 일반적인 경로 기반 필터(test/doc 패턴, 생성된 파일 탐지)가 생략됩니다 — Nelson은 사용자가 원하는 것을 알고 있다고 신뢰합니다. nelson inventory와 nelson haha에도 동일하게 적용됩니다.```bash
nelson scan path/to/suspicious.py
nelson scan src/api/*.py
nelson scan src/auth.py src/db.py src/handlers/*.go
nelson inventory src/api/*.py nelson haha src/auth.py src/db.py
스캔은 재개 가능합니다. 중단된 경우 스캔 ID로 재개하세요:```bash
nelson scan --resume 3
리뷰 패스는 먼저 스캔 결과를 중복 제거하여 클러스터로 묶습니다(동일한 파일 및 CWE, --line-tolerance(기본값 2) 내의 라인 번호). 그런 다음 클러스터당 하나의 대표 샘플을 전체 소스 파일과 함께 모델(가급적 스마트한 모델)에 전송하여 실행 흐름을 추적하고 취약점이 도달 가능하고 현실적인지 평가하도록 요청합니다. 결과 판정은 클러스터의 모든 발견 항목에 적용되므로, --repeat 및 여러 모델이 여러 번 발견한 버그는 한 번만 평가됩니다. 즉, 리뷰어가 동일한 발견에 대해 반복해서 비용을 지불하지 않습니다. 중복 행은 모두 유지되며(해당 행을 발견한 모델/패스 정보 포함) 비교 보기가 계속 작동합니다.```bash
nelson review
nelson review 3
nelson review -m claude:opus
nelson review --line-tolerance 5
nelson review -m "lmstudio:Qwen/Qwen3-27B" --tools
각 결과물은 `confirmed`, `false_positive`, `needs_review`, 또는 `resolved`(스캔 이후 파일이 삭제된 경우) 판정을 받습니다. `--tools` 플래그는 `nelson scan`과 동일하게 작동합니다. OpenAI 호환 모델(`openai:`/`lmstudio:`/`ollama:`)에 대해 스캔된 트리 위에서 읽기 전용 `read_file`/`grep`/`list_dir` 루프를 제공하여, 결과물이 관련된 파일을 추적한 후 도달 가능성을 판단할 수 있게 합니다. `claude:`/`gemini:`의 경우 이미 자체적으로 파일을 읽으므로 아무 작업도 하지 않습니다. 검토는 멱등적입니다. 다시 실행하면 아직 검토되지 않은 결과물만 처리하므로, 한 모델로 검토한 후 다른 모델로 두 번째 패스를 실행할 수 있습니다.
### Reporting```bash
# Show all findings from the latest scan
nelson report