| name | hae |
|---|---|
| description | Scans files and directories for fingerprints, secrets and sensitive data using HaE rules (ripgrep + PCRE2), then emits a deduplicated JSON report. Use when the user asks to scan source code, JS bundles, logs, packet dumps or any local files for leaked keys, tokens, JWT, credentials, emails, phone numbers, ID cards, internal URLs, API endpoints or framework fingerprints, or when the user mentions HaE, HaE rules, Rules.json or sensitive information scanning. |
HaE Skill
Rule-driven sensitive information scanning for local files. Rules come from
rules/Rules.json (HaE rule set); matching is done by ripgrep and the artifact
is a single JSON report. Nothing outside the Python standard library is needed —
ripgrep on PATH is the only requirement.
Quick Start
A target is always required — the scanner never defaults to the current directory. Invoke the scanner through this Skill's own directory, since the working directory is usually some other project:
python3 <skill-dir>/scripts/hae_scan.py /abs/path/to/target
<skill-dir> is the directory this SKILL.md lives in.
The command writes .hae/hae-scan-<timestamp>.json under the current directory and
prints a per-rule summary to stdout. Read the JSON for details, not the whole file
tree.
Workflow
Task Progress:
- [ ] Step 1: Confirm the explicit scan target
- [ ] Step 2: Run the scan
- [ ] Step 3: Read summary, then drill into findings
- [ ] Step 4: Verify high-value hits against the source lines
- [ ] Step 5: Report grouped results with file:line references
Step 1: Confirm the target. Ask for a path if the user did not give one. Do not
guess and do not scan /, $HOME or an entire disk. For a big tree, narrow with
--ignore-ext or point at a subdirectory.
Step 2: Run the scan.
python3 <skill-dir>/scripts/hae_scan.py /path/to/app/dist /path/to/app/src
Add --group / --rule when the user only cares about one class of data:
python3 <skill-dir>/scripts/hae_scan.py /path/to/target --group "Sensitive Information" --group "Basic Information"
Step 3: Read the report. The stdout summary gives per-rule counts. Then read the
JSON findings array, filtering with a small query instead of dumping the file:
python3 -c "
import json,sys
d=json.load(open(sys.argv[1]))
for f in d['findings']:
if f['group'] in ('Sensitive Information','Basic Information','Maybe Vulnerability'):
loc=f['locations'][0]
print(f\"{f['group']}/{f['rule']}\t{f['match']}\t{loc['file']}:{loc['line']}:{loc['column']}\tx{f['count']}\")
" .hae/hae-scan-<timestamp>.json
Step 4: Verify before reporting. HaE rules are recall-oriented and produce false positives, especially on source code. Confirm high-value hits by reading the actual line:
sed -n '120,124p' /path/to/file
Treat as noise unless context proves otherwise: placeholder values (example.com,
13800138000, xxx), test fixtures, vendored dependencies, minified library
internals.
Step 5: Report. Group by rule group, lead with what is actionable, and always
cite file:line. See the reporting template below.
Options
| Option | Default | Purpose |
|---|---|---|
targets | required | One or more files/directories |
--rules PATH | <skill-dir>/rules/Rules.json | Alternative rule set using the same reduced schema |
--group NAME | all | Keep groups whose name contains NAME (repeatable) |
--rule NAME | all | Keep rules whose name contains NAME (repeatable) |
-o, --out PATH | .hae/hae-scan-<ts>.json | Output path; - streams JSON to stdout |
--context N | 50 | Context characters kept around each match, 0 disables |
--max-locations N | 5 | Locations kept per unique match value, 0 = all |
--max-matches N | 200 | Unique match values kept per rule, 0 = all |
--max-count N | 0 | ripgrep --max-count per file, 0 = unlimited |
--max-filesize SIZE | 10M | Skip larger files; empty string = unlimited |
--ignore-ext EXT | image extensions | Extension to skip (repeatable, replaces defaults) |
--timeout SEC | 180 | Per-pattern ripgrep timeout, 0 = none |
--jobs N | 8 | Parallel ripgrep processes |
--list-rules | off | Print the loaded rules as JSON and exit |
Report Shape
{
"meta": {
"targets": ["/abs/path"], "rules_file": "...", "rules_scanned": 41,
"patterns_executed": 41, "duration_ms": 94,
"ripgrep": { "path": "/opt/homebrew/bin/rg", "version": "ripgrep 15.1.0" },
"errors": [{ "rules": ["Group/Rule"], "message": "..." }],
"capped_rules": ["Other/Request URI"]
},
"summary": {
"total_matches": 9216, "unique_matches": 284, "files_with_matches": 29,
"groups": [{ "group": "Other", "total": 9136, "unique": 242,
"rules": [{ "rule": "Request URI", "total": 9055, "unique": 200, "files": 29 }] }]
},
"findings": [
{ "group": "Basic Information", "rule": "Email", "match": "zhangsan@example.com",
"count": 3, "locations_omitted": 0,
"locations": [{ "file": "/abs/f.js", "line": 1, "column": 17,
"context": { "before": "// contact ", "after": " for support" } }] }
]
}
Findings are deduplicated per (group, rule, match); count is the number of
distinct locations and locations_omitted records what --max-locations dropped.
line and column are 1-based.
Always check meta.errors and meta.capped_rules: an error means that rule produced
nothing, and a capped rule means results were truncated — rerun with --rule "<name>" --max-matches 0 if it matters.
Reporting Template
## HaE 扫描结果
**目标**: /path/to/target
**规模**: 41 条规则,<N> 处匹配(<U> 个去重值),<F> 个文件命中
### 需要处理
- **<Rule>** — `<match>` @ [file:line](file:///abs/path#L12)
说明为什么这条值得处理
### 可能有价值
- **<Rule>** — <N> 处,示例 `<match>`(file:line)
### 已判定为噪音
- <Rule>:<N> 处,均为测试数据/第三方依赖
**报告文件**: .hae/hae-scan-<timestamp>.json
Rule Groups
| Group | Content | Signal |
|---|---|---|
| Fingerprint | Shiro, JWT, Swagger UI, Druid, Vite DevMode, … | High — tells you what the target runs |
| Maybe Vulnerability | Java deserialization, debug parameters, upload forms, … | Medium — needs manual confirmation |
| Basic Information | Email, phone, ID card, IP, domain | Medium — verify it is real data, not fixtures |
| Sensitive Information | Keys, tokens, credential fields, cloud AK/SK, auth fields | Highest priority |
| Other | Linkfinder, All URL, Request URI, Source Map | Low — inventory material, very noisy |
Request URI, Linkfinder, All URL and Userinfo In Link fire heavily on ordinary
source code. Report them as counts and examples, never as full listings.
Rules Maintenance
rules/Rules.json is a copy of the HaE rule set reduced to what file scanning needs:
{
"rules": [
{
"group": "Fingerprint",
"rule": [
{ "name": "Shiro", "loaded": true, "regex": "(=deleteMe|rememberMe=)", "sensitive": true }
]
}
]
}
Only group, name, loaded, regex, sensitive are used. HaE's HTTP-oriented
fields (scope, engine, color, validator) and the two-stage s_regex / format
extraction are intentionally dropped — this Skill has no HTTP message to scope, no
UI to color and no request context to validate against.
To add or refresh rules, edit this file directly: copy the rule from a HaE rule set,
rename f_regex to regex and drop the other fields. HaE ships its rules as YAML, and
--rules still accepts a .yml file when PyYAML happens to be installed. The field
mapping is in reference.md.
Additional Resources
For rule field semantics, the ripgrep invocation, capture-group extraction, the HaE field mapping and troubleshooting, see reference.md.
