|
193 | 193 | gf: { |
194 | 194 | columns: [ |
195 | 195 | { id: 'target', label: 'TARGET', flex: '2', type: 'link' }, |
| 196 | + { id: 'sev', label: 'SEV', w: '68px', type: 'sev-badge', align: 'center' }, |
196 | 197 | { id: 'pattern', label: 'PATTERN', flex: '1', type: 'badge-pill' }, |
197 | | - { id: 'value', label: 'VALUE', flex: '3', type: 'mono-trunc' }, |
198 | | - { id: 'source', label: 'SOURCE', flex: '1', type: 'muted-trunc' }, |
| 198 | + { id: 'value', label: 'MATCHED URL', flex: '3', type: 'mono-trunc' }, |
199 | 199 | ], |
200 | 200 | extract(r) { |
| 201 | + const raw = r.raw || {}; |
201 | 202 | const target = s(r.host || r.target || '-'); |
202 | | - |
203 | | - let patternName = s(r.pattern || r.finding_type || ''); |
| 203 | + |
| 204 | + // Resolve pattern name: prefer explicit raw.pattern → raw.template_id → r.finding → filename |
| 205 | + let patternName = s(raw.pattern || raw.template_id || ''); |
204 | 206 | if (!patternName && r.file) { |
205 | | - patternName = r.file.replace(/\.txt$/i, '').replace(/^gf-/i, ''); |
206 | | - } |
207 | | - if (!patternName) patternName = s(r.module || '—'); |
208 | | - |
209 | | - let valueStr = s(r.value || r.finding || '-'); |
210 | | - if (valueStr.toLowerCase() === 'gf-patterns' || valueStr.toLowerCase() === s(r.module).toLowerCase()) { |
211 | | - valueStr = '-'; |
| 207 | + patternName = r.file.replace(/\.txt$/i, '').replace(/^gf-/i, '').replace(/-results$/i, ''); |
212 | 208 | } |
| 209 | + if (!patternName) patternName = s(r.finding || r.module || '—'); |
| 210 | + // Strip leading "gf-" prefix for display (gf-ssrf → ssrf) |
| 211 | + const displayName = patternName.replace(/^gf-/i, ''); |
| 212 | + |
| 213 | + // Pattern → colour mapping |
| 214 | + const patternColors = { |
| 215 | + ssrf: '#f87171', rce: '#f87171', lfi: '#f87171', sqli: '#f87171', ssti: '#f87171', |
| 216 | + xss: '#fb923c', redirect: '#fbbf24', idor: '#fbbf24', iparams: '#fbbf24', debug_logic: '#fbbf24', |
| 217 | + iext: '#4ade80', 'img-traversal': '#4ade80', isubs: '#22d3ee', jsvar: '#22d3ee', |
| 218 | + }; |
| 219 | + const color = patternColors[displayName.toLowerCase()] || '#a78bfa'; |
| 220 | + |
| 221 | + // VALUE column: the actual matched URL (stored in target/host after backend parsing) |
| 222 | + const value = s(r.target || r.host || '-'); |
213 | 223 |
|
214 | 224 | return { |
215 | 225 | target: { href: toHref(target), label: target }, |
216 | | - pattern: { label: patternName, color: '#a78bfa' }, |
217 | | - value: valueStr, |
218 | | - source: s(r.file || r.source || '—'), |
| 226 | + sev: sevMeta(r.severity), |
| 227 | + pattern: { label: displayName || patternName, color }, |
| 228 | + value, |
219 | 229 | }; |
220 | 230 | }, |
| 231 | + detail(r) { |
| 232 | + const raw = r.raw || {}; |
| 233 | + const patternName = s(raw.pattern || raw.template_id || r.finding || ''); |
| 234 | + return buildFields([ |
| 235 | + ['Pattern', patternName.replace(/^gf-/i, '')], |
| 236 | + ['Full ID', patternName], |
| 237 | + ['Matched URL', s(r.target || r.host || ''), { isLink: true }], |
| 238 | + ['Severity', s(r.severity)], |
| 239 | + ['Source File', s(r.file || raw.module || '')], |
| 240 | + ]); |
| 241 | + }, |
221 | 242 | }, |
222 | 243 |
|
| 244 | + |
223 | 245 | /* ── JS Analysis ────────────────────────────────────────────────────── */ |
224 | 246 | js: { |
225 | 247 | columns: [ |
|
0 commit comments