{"id":48268190,"url":"https://github.com/tosanjay/NeuroLog","last_synced_at":"2026-04-20T10:01:12.945Z","repository":{"id":349711098,"uuid":"1196734041","full_name":"tosanjay/NeuroLog","owner":"tosanjay","description":null,"archived":false,"fork":false,"pushed_at":"2026-04-07T06:58:28.000Z","size":147,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-07T08:30:41.119Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tosanjay.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-31T01:46:31.000Z","updated_at":"2026-04-07T06:58:34.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/tosanjay/NeuroLog","commit_stats":null,"previous_names":["tosanjay/neurolog"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/tosanjay/NeuroLog","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tosanjay%2FNeuroLog","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tosanjay%2FNeuroLog/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tosanjay%2FNeuroLog/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tosanjay%2FNeuroLog/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tosanjay","download_url":"https://codeload.github.com/tosanjay/NeuroLog/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tosanjay%2FNeuroLog/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32042293,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-20T00:18:06.643Z","status":"online","status_checked_at":"2026-04-20T02:00:06.527Z","response_time":94,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-04-04T22:00:29.175Z","updated_at":"2026-04-20T10:01:12.937Z","avatar_url":"https://github.com/tosanjay.png","language":"Python","funding_links":[],"categories":["Python"],"sub_categories":[],"readme":"```\n    _   _                      _\n   | \\ | | ___ _   _ _ __ ___ | |    ___   __ _\n   |  \\| |/ _ \\ | | | '__/ _ \\| |   / _ \\ / _` |\n   | |\\  |  __/ |_| | | | (_) | |__| (_) | (_| |\n   |_| \\_|\\___|\\__,_|_|  \\___/|_____\\___/ \\__, |\n                                           |___/\n   Neuro-Symbolic Static Analysis via Datalog\n\n   Neuro  =  LLM perceives code, extracts semantic facts\n   Log    =  Datalog reasons formally over those facts\n```\n\n# NeuroLog\n\n**Compilation-free static analysis for C/C++ using neuro-symbolic reasoning: LLM perception + Datalog logic.**\n\nNeuroLog is a neuro-symbolic static analysis research prototype that extracts and reasons about program properties from C/C++ source code — without requiring compilation. The **neural** component (an LLM) reads raw source code and extracts structured Datalog facts representing data flow, control flow, type information, and function relationships; the **symbolic** component (Souffle Datalog) performs formal interprocedural reasoning over those facts.\n\nThe extracted fact base is general-purpose: the same facts support taint analysis, memory safety checks, type safety reasoning, crypto API misuse detection, and any other property expressible in Datalog. Users can write custom Datalog rules to query arbitrary program properties.\n\n## Key Idea\n\nTraditional static analysis tools require a complete build environment to produce an intermediate representation (AST, CFG, SSA). This is a significant barrier for analyzing legacy code, partial codebases, or projects with complex build systems.\n\n**NeuroLog replaces the compiler frontend with an LLM.** The LLM reads C source directly and emits the same structured facts (Def, Use, Call, Guard, MemWrite, etc.) that a compiler-based extractor would produce. These facts feed into standard Datalog rules for interprocedural analysis — no compilation, no headers, no build system required.\n\nBecause the reasoning layer is Datalog, the analysis is **extensible by writing rules, not code**. Adding a new analysis (e.g., detecting insecure crypto API usage, checking resource leak patterns, or enforcing coding standards) requires only new `.dl` rule files — the fact extraction is reused as-is.\n\n```\n                          NEURAL                          SYMBOLIC\n                    ┌─────────────────┐\n   C source ───────►│  tree-sitter    │──── function list, call graph, sink detection\n                    │  (fast, free)   │──── backward slice --\u003e targeted function set\n                    └────────┬────────┘\n                             │\n                    ┌────────▼────────┐\n   targeted funcs ─►│  LLM (Claude)   │──── Datalog facts (Def, Use, Call, Guard,\n                    │  (perception)   │     MemWrite, Cast, ArithOp, VarType, ...)\n                    └────────┬────────┘\n                             │              ┌──────────────────────────────────────┐\n                    ┌────────▼────────┐     │  Data/control flow properties        │\n   .facts files ───►│  Souffle        │────►│  Security (taint, memory, type)      │\n                    │  (reasoning)    │     │  Custom queries (crypto, resources)  │\n                    └─────────────────┘     └──────────────────────────────────────┘\n```\n\n## What Can You Analyze?\n\nNeuroLog's fact base captures definitions, uses, calls, control flow edges, guards, memory operations, types, and casts for every function. This enables a range of analyses:\n\n| Analysis Domain | Example Queries | Status |\n|----------------|-----------------|--------|\n| **Interprocedural taint** | Does user input reach `strcpy`? Does a network buffer flow to `system()`? | Implemented |\n| **Memory safety** | Buffer overflow in loops, use-after-free, double-free, tainted allocation sizes | Implemented |\n| **Type safety** | Signed/unsigned mismatches on tainted data, truncation casts, width mismatches | Implemented |\n| **Crypto API misuse** | Does a hardcoded key reach `EVP_EncryptInit`? Is `ECB` mode used with AES? Is `rand()` used for key generation? | Planned |\n| **Resource leaks** | Is a file descriptor opened but never closed on some path? | Planned |\n| **Custom properties** | Any interprocedural data/control flow property expressible in Datalog | Write your own `.dl` rules |\n\n### Note on LLM Model\n\nAll evaluation results were obtained using **Claude Sonnet 4.6** (`anthropic/claude-sonnet-4-6`). The quality of extracted facts — and therefore the accuracy of downstream analyses — depends on the LLM's ability to understand C code semantics. Results may vary with different models or model versions. The pipeline is model-agnostic via LiteLLM and can be configured to use any supported LLM (see `.env`), but we recommend using a frontier-class model for best results.\n\n## Evaluation Results\n\n### Phase 3A: Synthetic Benchmark (20 files, 90 functions)\n\nCompared against **Joern** (a traditional CPG-based analysis tool) on 5 vulnerability categories:\n\n| Metric | NeuroLog | Joern |\n|--------|-------------|-------|\n| File-level recall | 92.3% | 86.7% |\n| Sink-level F1 | 63.4% | — |\n| UAF/DoubleFree detection | Yes (intraprocedural) | Yes |\n| Type safety findings | 147 across 20 files | — |\n| Memory safety findings | 540 across 20 files | — |\n| Compilation required | No | No |\n| Cost per file | ~$0.12 (batch) | $0 (local) |\n| Wall-clock (20 files) | 3.7 min (batch) | 2 min |\n\nOn overlapping analysis scope (interprocedural data taint), agreement is strong at the sink-type level. Disagreements are due to different analysis capabilities: we find tainted-size allocation sinks and type safety issues; Joern finds UAF lifecycle issues via PDG reachability. The 5-pass pipeline additionally detects use-after-free, double-free, buffer overflow in loops, and signedness mismatches.\n\nFull report: [`eval/results/phase3a_evaluation_report.md`](eval/results/phase3a_evaluation_report.md)\n\n### Real-World Validation: cJSON v1.7.17\n\nApplied to the [cJSON](https://github.com/DaveGamble/cJSON) JSON parser (31 functions, ~2,500 LOC). The pipeline detects:\n\n| CVE | Type | Detection |\n|-----|------|-----------|\n| **CVE-2023-53154** | Heap buffer over-read in `parse_string` | BufferOverflowInLoop at lines 830/844/882 |\n| **CVE-2025-57052** | OOB array access in `cJSON_Utils.c` | TaintedSink: `get_array_item` with `oob_access` |\n| CVE-2023-26819 | DoS in `parse_number` | TaintedLoopBound (partial — no explicit DoS category) |\n\nThe CVE-2025-57052 detection traces taint across 4 functions: `apply_patch` → `get_item_from_pointer` → `decode_array_index_from_pointer` (writes tainted index via output param) → `get_array_item` (OOB access with unchecked index).\n\nTotal cJSON analysis cost: ~$2.12\n\nFull report: [`eval/results/cjson_evaluation_report.md`](eval/results/cjson_evaluation_report.md)\n\n## Quick Start\n\n### Prerequisites\n\n- Python 3.11+\n- [Souffle](https://souffle-lang.github.io/) Datalog compiler\n- [Google ADK](https://google.github.io/adk-docs/) (`pip install google-adk`)\n- tree-sitter + tree-sitter-c (`pip install tree-sitter tree-sitter-c`)\n- LiteLLM (`pip install litellm`)\n- An Anthropic API key:\n  ```bash\n  cp .env.example .env\n  # Edit .env and add your ANTHROPIC_API_KEY\n  ```\n\n### Interactive Mode (Recommended)\n\nNeuroLog includes a Google ADK agent that provides an interactive web UI. The agent orchestrates the full pipeline — scanning, fact extraction, Souffle analysis — through natural language:\n\n```bash\n# Launch the interactive web UI\nuv run adk web\n\n# Or via adk directly\nadk web\n```\n\nThen open the browser at `http://localhost:8000` and select the **SourceCodeQL** agent. You can interact with it conversationally:\n\n\u003e \"Scan /path/to/project and find dangerous sinks\"\n\u003e \"Extract facts for parse_string in cJSON.c\"\n\u003e \"Run the taint pipeline and show me the findings\"\n\nThe agent uses a **multi-agent coordinator architecture** designed for large projects:\n\n- **Coordinator** — routes requests, runs the full pipeline tool\n- **ExtractionAgent** — LLM fact extraction (uses `LITE_MODEL_NAME` for cost efficiency)\n- **AnalysisAgent** — Souffle Datalog queries and custom rule composition\n- **InterpreterAgent** — reads results, interprets findings, generates reports\n- **CVEAgent** — searches NIST NVD for known CVEs matching findings (uses `LITE_MODEL_NAME`)\n\nFor large projects, use `tool_run_full_pipeline(project_dir)` — it runs the entire scan-extract-analyze pipeline as pure computation and returns only a compact summary, avoiding context window overflow.\n\n#### Cost Optimization\n\nBy default, all agents use `MODEL_NAME`. For significant cost savings, set `LITE_MODEL_NAME` in `.env` to use a cheaper model for sub-agents that don't need deep reasoning:\n\n```bash\n# In .env\nMODEL_NAME=\"anthropic/claude-opus-4-6\"          # For analysis \u0026 interpretation\nLITE_MODEL_NAME=\"anthropic/claude-sonnet-4-6\"    # For extraction routing \u0026 CVE lookup (~10x cheaper)\n```\n\n| Agent | Model Used | Why |\n|-------|-----------|-----|\n| Coordinator | `MODEL_NAME` | Needs to understand user intent and route |\n| ExtractionAgent | `LITE_MODEL_NAME` | Orchestrates extraction calls, no deep reasoning |\n| AnalysisAgent | `MODEL_NAME` | Composes Datalog queries, interprets formal results |\n| InterpreterAgent | `MODEL_NAME` | Deep reasoning for vulnerability assessment |\n| CVEAgent | `LITE_MODEL_NAME` | Calls NVD API and formats results |\n\n### Command-Line Mode\n\nIndividual pipeline stages can also be run directly:\n\n```bash\n# 1. Scan a project: enumerate functions, find dangerous sinks, compute backward slice\npython tree_sitter_nav.py \u003cproject_dir\u003e sinks\npython tree_sitter_nav.py \u003cproject_dir\u003e slice\n\n# 2. Extract Datalog facts for a function using LLM\npython llm_extractor.py \u003cfile.c\u003e \u003cfunc_name\u003e [output_dir]\n\n# 3. Run the full Souffle analysis pipeline (alias → taint → type safety → memory safety → sink post-pass)\npython souffle_runner.py pipeline [facts_dir] [output_dir]\n\n# Or run individual passes\npython souffle_runner.py alias.dl [facts_dir] [output_dir]\npython souffle_runner.py source_interproc.dl [facts_dir] [output_dir]\n```\n\n### Example: Analyzing a Single File\n\n```bash\n# Extract facts for all functions in a file\npython llm_extractor.py vulnerable.c process_input facts/\npython llm_extractor.py vulnerable.c handle_request facts/\n\n# Run the 5-pass pipeline\npython souffle_runner.py pipeline facts/ output/\n\n# Check results\ncat output/TaintedSink.csv          # Tainted data reaching dangerous sinks\ncat output/UnguardedTaintedSink.csv # Unguarded tainted sinks (highest priority)\ncat output/MemSafetyFinding.csv     # Memory safety violations\ncat output/TypeSafetyFinding.csv    # Type confusion findings\n```\n\n## Project Structure\n\n| File | Purpose |\n|------|---------|\n| `agent.py` | Google ADK agent — interactive web UI for the full pipeline (`adk web`) |\n| `tree_sitter_nav.py` | Project scanning, call graph, sink detection, backward slicing |\n| `llm_extractor.py` | LLM-based Datalog fact extraction from C source |\n| `batch_extractor.py` | Anthropic Batch API wrapper (8x faster, 50% cheaper) |\n| `fact_schema.py` | Fact schema (19 types), Fact dataclass, TSV writer |\n| `souffle_runner.py` | Souffle subprocess execution, 5-pass analysis pipeline |\n| `tree_sitter_facts.py` | Ground truth extraction (tree-sitter only, for comparison) |\n| `prompts/fact_extraction.md` | The LLM fact extraction prompt |\n| `rules/*.dl` | Souffle Datalog rule files (17 files) |\n| `eval/` | Phase 3A evaluation framework and results |\n\n## Architecture \u0026 Design\n\nFor detailed documentation of the Datalog rule architecture, fact schema, LLM extraction methodology, and analysis passes, see:\n\n**[`docs/datalog_arch_design.md`](docs/datalog_arch_design.md)**\n\nThis covers:\n- The 19-type fact schema and how facts map to C language constructs\n- How the LLM extracts facts directly from C source (the core innovation)\n- The 5-pass Souffle analysis pipeline\n- All Datalog rule files and their purposes\n- Interprocedural taint propagation mechanics\n- Defensive rules that compensate for LLM imprecision\n\n## Built-in Analyses\n\n### Security Properties (Implemented)\n\n| Property | Datalog Relation | Description |\n|----------|-----------------|-------------|\n| Tainted sink | `TaintedSink` | Untrusted data reaches a dangerous function (strcpy, malloc, free, etc.) |\n| Unguarded tainted sink | `UnguardedTaintedSink` | Tainted sink with no bounds check or NULL guard |\n| Use-after-free | `UseAfterFree` | Pointer used after being passed to free/deallocate |\n| Double-free | `DoubleFree` | Same pointer freed twice without reassignment |\n| Buffer overflow in loop | `BufferOverflowInLoop` | Tainted loop bound with buffer write in body |\n| Tainted allocation size | `TaintedSizeAtSink` | Tainted value used as allocation/copy size |\n| Signedness mismatch | `TaintedSignednessMismatch` | Signed/unsigned conversion on tainted data |\n| Truncation cast | `TruncationCast` | Narrowing cast that loses bits |\n| Type safety finding | `TypeSafetyFinding` | Combined type confusion findings |\n| Memory safety finding | `MemSafetyFinding` | Combined memory safety findings |\n\n### Data/Control Flow Properties (Reusable Foundation)\n\n| Relation | Description |\n|----------|-------------|\n| `TaintedVar` | Interprocedural taint propagation — tracks which variables carry untrusted data |\n| `DefReachesUse` | Reaching definitions — which definition of a variable is live at a given use |\n| `CFGReach` | Control flow reachability between program points |\n| `PointsTo` | Pointer alias analysis |\n| `TaintSummary` | Per-function taint transfer summaries (parameter → return/output) |\n\nThese relations are computed by the pipeline and available for custom downstream queries.\n\n### Writing Custom Analyses\n\nTo add a new analysis, create a `.dl` file in `rules/` that reads from the fact base. For example, to detect hardcoded keys passed to crypto functions:\n\n```prolog\n// crypto_misuse.dl — detect hardcoded keys reaching encryption APIs\n.decl DangerousCryptoSink(func: symbol, arg: number, risk: symbol)\n.input DangerousCryptoSink\n\n.decl HardcodedKeyAtCrypto(caller: symbol, callee: symbol, line: number, var: symbol)\n.output HardcodedKeyAtCrypto\n\n// Flag calls where a string literal or constant reaches a crypto key parameter\nHardcodedKeyAtCrypto(f, callee, ca, var) :-\n    Call(f, callee, ca),\n    DangerousCryptoSink(callee, idx, _),\n    ActualArg(ca, idx, _, var, _),\n    Def(f, var, da, \"const\"),\n    DefReachesUse(f, var, da, ca).\n```\n\nThen run: `python souffle_runner.py crypto_misuse.dl facts/ output/`\n\n## Comparison with Related Tools\n\n| Tool | Approach | Compilation | Language | Interprocedural | Cost |\n|------|----------|-------------|----------|-----------------|------|\n| **NeuroLog** | LLM extraction → Datalog | No | C/C++ | Yes (1-CFA) | ~$0.12/file |\n| [CodeQL](https://codeql.github.com/) | Compiler-based extraction → QL | Yes | 10+ languages | Yes | Free (OSS) |\n| [Joern](https://joern.io/) | Fuzzy parsing → CPG → Scala queries | No | C/C++, Java, ... | Yes | Free (OSS) |\n| [DOOP](https://bitbucket.org/yanniss/doop/) | Compiler-based → Datalog (Soufflé/LogicBlox) | Yes | Java/Android | Yes (deep) | Free (research) |\n| [Semgrep](https://semgrep.dev/) | Pattern matching on AST | No | 30+ languages | Limited | Free/Paid |\n| [Infer](https://fbinfer.com/) | Abstract interpretation (bi-abduction) | Yes | C/C++, Java, ObjC | Yes | Free (OSS) |\n\n**Key differentiator**: NeuroLog combines compilation-free analysis with formal Datalog-based interprocedural reasoning. CodeQL and DOOP require compilation; Joern and Semgrep don't use formal Datalog. The LLM serves as a \"semantic compiler\" that understands C without needing headers, build systems, or platform-specific toolchains. Because the reasoning layer is standard Datalog, users can write custom queries for any property — security, correctness, coding standards — without modifying the extraction pipeline.\n\n## TODO / Known Limitations\n\n### C++ Support\n\nThe current pipeline targets **C**. C++ codebases will parse and extract facts, but the analysis degrades on C++-specific constructs:\n\n| Construct | Impact | Workaround |\n|-----------|--------|------------|\n| **Virtual dispatch** | Polymorphic calls unresolved — `obj-\u003emethod()` doesn't connect to the concrete override | Analyze concrete classes directly |\n| **Templates** | `sizeof(T)` stays symbolic; no instantiation tracking | Manually instantiate target types |\n| **Exceptions** | No CFGEdge for throw/catch — reaching defs incomplete | Treat as C (misses exception paths) |\n| **RAII / Destructors** | Implicit `free()`/`fclose()` in destructors invisible | Manually add DangerousSink for RAII wrappers |\n| **Operator overloading** | `operator[]` is a Call, not MemWrite — buffer semantics lost | N/A |\n| **Lambdas** | Capture semantics not modeled; closure taint lost | Extract lambda body as separate function |\n| **Move semantics** | `std::move()` ownership transfer not tracked | N/A |\n| **STL containers** | `std::string`, `std::vector` — no library-specific taint models | Add signatures.dl entries for STL |\n\nSee [`docs/datalog_arch_design.md` § TODO](docs/datalog_arch_design.md#10-todo--future-work) for the full roadmap.\n\n### Analysis Limitations\n\n- **No path sensitivity**: Both feasible and infeasible paths are analyzed (same as Joern). Taint paths in \"fixed\" code are still flagged.\n- **Intraprocedural UAF only**: Use-after-free and double-free are detected within a single function. Interprocedural UAF (freed in callee, used in caller) is planned.\n- **1-CFA context depth**: Deeply nested call chains (\u003e1 indirect) lose precision. Upgrading to 2-CFA or object-sensitive analysis would help.\n- **No whole-program analysis**: Backward slicing limits scope — taint entering through non-sliced functions is missed.\n- **No incremental analysis**: Every run re-extracts and re-analyzes all functions.\n\n## Authors\n\n- **Sanjay Rawat**\n- **Claude Code** (Opus 4.6) — Anthropic\n\n## License\n\nThis project is licensed under the [Polyform Noncommercial 1.0.0](https://polyformproject.org/licenses/noncommercial/1.0.0/) license. Free for research, education, and personal use. Commercial use requires a separate license.\n\n## References\n\n- [Souffle Datalog](https://souffle-lang.github.io/) — The Datalog engine used for analysis\n- [DOOP](https://bitbucket.org/yanniss/doop/) — Points-to analysis for Java via Datalog (Smaragdakis \u0026 Balatsouras, 2015)\n- [CodeQL](https://codeql.github.com/) — GitHub's semantic code analysis engine\n- [Joern](https://joern.io/) — Code Property Graph analysis platform\n- [bddbddb](http://bddbddb.sourceforge.net/) — BDD-based Datalog for program analysis (Whaley \u0026 Lam, 2004)\n- [Datalog Disassembly](https://arxiv.org/abs/1906.03969) — GrammaTech's Datalog-based binary analysis (Flores-Montoya \u0026 Schulte, 2020)\n- [tree-sitter](https://tree-sitter.github.io/) — Incremental parsing library\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftosanjay%2FNeuroLog","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftosanjay%2FNeuroLog","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftosanjay%2FNeuroLog/lists"}