Vasanthakumar R commited on
Commit
9959ec6
·
1 Parent(s): 4ead543

Achilles Code Scanner — AI-powered SAST

Browse files
Files changed (3) hide show
  1. README.md +14 -6
  2. app.py +230 -0
  3. requirements.txt +6 -0
README.md CHANGED
@@ -1,12 +1,20 @@
1
  ---
2
  title: Achilles Code Scanner
3
- emoji: 🏃
4
- colorFrom: blue
5
- colorTo: blue
6
  sdk: gradio
7
- sdk_version: 6.11.0
8
  app_file: app.py
9
- pinned: false
 
 
10
  ---
11
 
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
1
  ---
2
  title: Achilles Code Scanner
3
+ emoji: 🔍
4
+ colorFrom: red
5
+ colorTo: red
6
  sdk: gradio
7
+ sdk_version: 5.12.0
8
  app_file: app.py
9
+ pinned: true
10
+ license: apache-2.0
11
+ suggested_hardware: t4-small
12
  ---
13
 
14
+ # Achilles Code Scanner
15
+
16
+ AI-powered Static Application Security Testing (SAST) by **HTS-ASPM**.
17
+
18
+ Paste code in any language — get instant vulnerability analysis with CWE mapping, severity, root cause, and fixes.
19
+
20
+ **Supported:** Python, JavaScript, TypeScript, PHP, C, C++, Java, Ruby, Go, Rust
app.py ADDED
@@ -0,0 +1,230 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Achilles Code Scanner — HuggingFace Space
3
+ AI-powered SAST: paste code, find vulnerabilities.
4
+
5
+ Deploy:
6
+ 1. Create Space on huggingface.co (Gradio SDK, T4 Small GPU)
7
+ 2. Upload this directory
8
+ 3. Set secrets: HF_MODEL (your fine-tuned SAST model or base model)
9
+ """
10
+
11
+ import os
12
+ import gradio as gr
13
+ import torch
14
+ from transformers import AutoModelForCausalLM, AutoTokenizer
15
+
16
+ # ── Model ───────────────────────────────────────────────────────
17
+ MODEL_ID = os.environ.get("HF_MODEL", "Qwen/Qwen2.5-Coder-1.5B-Instruct")
18
+ ADAPTER_ID = os.environ.get("HF_ADAPTER", "")
19
+
20
+ SYSTEM_PROMPT = (
21
+ "You are Achilles, an elite AI Security Engineer. "
22
+ "You ONLY report genuine vulnerabilities — you never raise false positives. "
23
+ "You ALWAYS provide a response — never return empty output."
24
+ )
25
+
26
+ device = "cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu"
27
+ dtype = torch.float16 if device != "cpu" else torch.float32
28
+
29
+ print(f"Loading {MODEL_ID} on {device}...")
30
+ tokenizer = AutoTokenizer.from_pretrained(MODEL_ID, trust_remote_code=True)
31
+ if tokenizer.pad_token is None:
32
+ tokenizer.pad_token = tokenizer.eos_token
33
+
34
+ model = AutoModelForCausalLM.from_pretrained(
35
+ MODEL_ID, torch_dtype=dtype, device_map="auto", trust_remote_code=True,
36
+ )
37
+
38
+ if ADAPTER_ID:
39
+ from peft import PeftModel
40
+ model = PeftModel.from_pretrained(model, ADAPTER_ID)
41
+
42
+ model.eval()
43
+ print("Model ready!")
44
+
45
+
46
+ # ── Inference ───────────────────────────────────────────────────
47
+ def scan_code(language: str, code: str, max_tokens: int = 1024) -> str:
48
+ if not code.strip():
49
+ return "Paste some code to scan."
50
+
51
+ user_msg = f"Analyze the following {language} code for security vulnerabilities:\n\n```{language}\n{code}\n```"
52
+ prompt = (
53
+ f"<|im_start|>system\n{SYSTEM_PROMPT}<|im_end|>\n"
54
+ f"<|im_start|>user\n{user_msg}<|im_end|>\n"
55
+ f"<|im_start|>assistant\n"
56
+ )
57
+
58
+ inputs = tokenizer(prompt, return_tensors="pt", truncation=True, max_length=4096).to(model.device)
59
+
60
+ with torch.no_grad():
61
+ outputs = model.generate(
62
+ **inputs,
63
+ max_new_tokens=max_tokens,
64
+ temperature=0.3,
65
+ top_p=0.9,
66
+ do_sample=True,
67
+ repetition_penalty=1.1,
68
+ pad_token_id=tokenizer.pad_token_id,
69
+ )
70
+
71
+ response = tokenizer.decode(outputs[0][inputs["input_ids"].shape[1]:], skip_special_tokens=True)
72
+ if "<|im_end|>" in response:
73
+ response = response[:response.index("<|im_end|>")]
74
+ return response.strip()
75
+
76
+
77
+ # ── Examples ────────────────────────────────────────────────────
78
+ EXAMPLES = [
79
+ ["python", '''import sqlite3, sys
80
+
81
+ def get_user(username):
82
+ conn = sqlite3.connect("app.db")
83
+ query = f"SELECT * FROM users WHERE username = '{username}'"
84
+ return conn.execute(query).fetchone()
85
+
86
+ print(get_user(sys.argv[1]))'''],
87
+
88
+ ["javascript", '''const express = require('express');
89
+ const { exec } = require('child_process');
90
+ const app = express();
91
+
92
+ app.get('/ping', (req, res) => {
93
+ exec(`ping -c 3 ${req.query.host}`, (err, stdout) => {
94
+ res.send(`<pre>${stdout}</pre>`);
95
+ });
96
+ });
97
+
98
+ app.listen(3000);'''],
99
+
100
+ ["php", '''<?php
101
+ $file = $_GET["page"];
102
+ include("/var/www/templates/" . $file);
103
+ ?>'''],
104
+
105
+ ["c", '''#include <stdio.h>
106
+ #include <string.h>
107
+
108
+ void process_input(char *input) {
109
+ char buffer[64];
110
+ strcpy(buffer, input);
111
+ printf("Processed: %s\\n", buffer);
112
+ }
113
+
114
+ int main(int argc, char *argv[]) {
115
+ if (argc > 1) process_input(argv[1]);
116
+ return 0;
117
+ }'''],
118
+
119
+ ["java", '''import java.io.*;
120
+ import javax.servlet.http.*;
121
+
122
+ public class FileServlet extends HttpServlet {
123
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
124
+ String filename = req.getParameter("file");
125
+ FileInputStream fis = new FileInputStream("/uploads/" + filename);
126
+ byte[] data = fis.readAllBytes();
127
+ resp.getOutputStream().write(data);
128
+ }
129
+ }'''],
130
+
131
+ ["ruby", '''class UsersController < ApplicationController
132
+ def search
133
+ @users = User.where("name LIKE '%#{params[:q]}%'")
134
+ render json: @users
135
+ end
136
+ end'''],
137
+
138
+ ["typescript", '''import express from 'express';
139
+ const app = express();
140
+ app.use(express.json());
141
+
142
+ app.post('/api/login', async (req, res) => {
143
+ const user = await db.collection('users').findOne({
144
+ email: req.body.email,
145
+ password: req.body.password
146
+ });
147
+ res.json({ user });
148
+ });'''],
149
+
150
+ ["go", '''package main
151
+
152
+ import (
153
+ "database/sql"
154
+ "fmt"
155
+ "net/http"
156
+ )
157
+
158
+ func handler(w http.ResponseWriter, r *http.Request) {
159
+ name := r.URL.Query().Get("name")
160
+ query := fmt.Sprintf("SELECT * FROM users WHERE name = '%s'", name)
161
+ rows, _ := db.Query(query)
162
+ defer rows.Close()
163
+ }'''],
164
+ ]
165
+
166
+ # ── UI ──────────────────────────────────────────────────────────
167
+ LANG_CHOICES = ["python", "javascript", "typescript", "php", "c", "cpp", "java", "ruby", "go", "rust"]
168
+
169
+ CSS = """
170
+ .header { text-align: center; padding: 24px 0 12px; }
171
+ .header h1 { color: #dc2626; font-size: 2.4em; margin: 0; letter-spacing: -0.02em; }
172
+ .header .sub { color: #94a3b8; margin: 4px 0 0; font-size: 1em; }
173
+ .header .brand { color: #475569; font-size: 0.8em; margin-top: 6px; }
174
+ .status-bar { background: #1e293b; border-radius: 8px; padding: 10px 16px; margin: 0 0 16px;
175
+ display: flex; justify-content: space-between; align-items: center; }
176
+ .status-bar span { color: #94a3b8; font-size: 0.85em; }
177
+ .status-bar .model { color: #22c55e; font-weight: 600; }
178
+ .status-bar .device { color: #f59e0b; }
179
+ footer { display: none !important; }
180
+ """
181
+
182
+ with gr.Blocks(
183
+ title="Achilles Code Scanner",
184
+ theme=gr.themes.Base(primary_hue="red", secondary_hue="slate", neutral_hue="slate",
185
+ font=gr.themes.GoogleFont("Inter")),
186
+ css=CSS,
187
+ ) as demo:
188
+
189
+ gr.HTML(f"""
190
+ <div class="header">
191
+ <h1>ACHILLES</h1>
192
+ <p class="sub">AI-Powered Code Vulnerability Scanner</p>
193
+ <p class="brand">Built by HTS-ASPM</p>
194
+ </div>
195
+ <div class="status-bar">
196
+ <span>Model: <span class="model">{MODEL_ID.split('/')[-1]}</span></span>
197
+ <span>Device: <span class="device">{device.upper()}</span></span>
198
+ <span>Languages: 10 supported</span>
199
+ </div>
200
+ """)
201
+
202
+ with gr.Row(equal_height=True):
203
+ with gr.Column(scale=1):
204
+ lang = gr.Dropdown(choices=LANG_CHOICES, value="python", label="Language")
205
+ code_input = gr.Code(label="Paste your code", language="python", lines=18)
206
+ with gr.Row():
207
+ max_tok = gr.Slider(256, 2048, value=1024, step=128, label="Max tokens")
208
+ scan_btn = gr.Button("Scan for Vulnerabilities", variant="primary", size="lg")
209
+
210
+ with gr.Column(scale=1):
211
+ output = gr.Markdown(label="Security Analysis")
212
+
213
+ scan_btn.click(fn=scan_code, inputs=[lang, code_input, max_tok], outputs=output)
214
+
215
+ with gr.Accordion("Example Vulnerabilities", open=False):
216
+ gr.Examples(
217
+ examples=EXAMPLES,
218
+ inputs=[lang, code_input],
219
+ label="Click to load",
220
+ )
221
+
222
+ gr.HTML("""
223
+ <p style="text-align:center; color:#475569; font-size:0.78em; padding:12px;">
224
+ Achilles Code Scanner &mdash; Results are AI-generated. Always verify findings with manual review.
225
+ </p>
226
+ """)
227
+
228
+
229
+ if __name__ == "__main__":
230
+ demo.launch(server_name="0.0.0.0", server_port=7860)
requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ gradio>=5.0.0
2
+ transformers>=4.45.0
3
+ torch>=2.1.0
4
+ peft>=0.13.0
5
+ accelerate>=1.0.0
6
+ huggingface_hub>=0.25.0