hashcheck
Investigate one file — identified by its hash — and give a malware analyst a
briefing they can act on in under a minute. If the user gives you a file instead
of a hash, compute its SHA-256 first (see "Accept files and batches"). A verdict
of benign, suspicious, or malicious is the point; get there and justify it.
Don't dump raw API output. Synthesize. Pull detections, code-signing, file
structure, and sandbox behavior into one picture, then make a defensible call
about how much to worry.
This is passive reconnaissance. You look up what public malware databases
already know about a hash. You never detonate the sample, download and run it,
submit it anywhere without saying so, or reach out to attacker infrastructure.
The hash is a fingerprint; treat this as a records check on that fingerprint. If
a user asks hashcheck to execute or actively probe a sample, decline that part
and explain that hashcheck is read-only.
What the verdict rests on
A hash lookup answers four questions. Weight them in this order.
- Consensus detection. How many reputable engines flag this file, and what
do they call it? A high, consistent detection count with an agreed family
name (e.g. "Emotet", "AgentTesla") is the strongest single signal. A handful
of generic "heuristic" or "ML" hits on an otherwise clean file is weak.
- Code-signing and provenance. A file signed by a named, reputable vendor
with a currently-valid certificate that VirusTotal verifies is far more
trustworthy than an unsigned one. A broken, expired, revoked, or
mismatched signature is worse than no signature at all, because it signals
tampering or impersonation. Read who signed it, not just whether it is signed.
- File structure. For Windows PE files, section entropy and layout betray
packing and obfuscation. A section with entropy above ~7.2 is likely packed
or encrypted — common in malware, but also in legitimate installers, so it is
a flag, not a conviction. An unusual section name (
.UPX0, .themida), a
tiny import table, or a mismatch between the file type and its extension all
deserve a mention.
- Sandbox behavior and corroboration. Dynamic-analysis verdicts, dropped
files, network indicators, and YARA/Sigma matches turn "some engines flag it"
into "here is what it does." Reach for these when the static picture is
ambiguous or the user is working an active incident.
Absence of evidence is not evidence of safety. A hash no database has seen is
unknown, not clean — say so, and lean on structure and signing to reason
about it.
Network access: pick the working path first
hashcheck depends on reaching public malware-intel APIs. How you reach them
varies by environment, and choosing wrong produces a page of connection errors
instead of a report.
- The bundled script
scripts/hashcheck.py. This runs every lookup at once
and prints a single compact JSON object. It works where the shell has
internet and the API keys are set as environment variables, such as Claude
Code on a workstation. It queries the richer, authenticated endpoints —
VirusTotal v3 (pe_info, signature_info, sandbox verdicts),
MalwareBazaar, Hybrid Analysis, and Joe Sandbox — that need custom headers
the WebFetch tool cannot send. Prefer this path whenever a shell with egress
exists: python3 scripts/hashcheck.py <hash-or-file>.
- The WebFetch tool (
mcp__workspace__web_fetch or WebFetch) plus
WebSearch. Use this in Cowork and other sandboxes where the shell has no
outbound internet. WebFetch can only issue GET requests and cannot set the
Auth-Key, x-apikey, or api-key headers the deep endpoints require, so on
this path you get VirusTotal's v2 endpoint (which accepts the key as a
query parameter) for the multi-engine verdict, plus WebSearch for
corroboration. You will usually not get PE sections, entropy, or signing
detail on this path — say so in the report rather than inventing it.
Try the script first when a shell exists. If its output contains
Tunnel connection failed, network unreachable, name resolution, or every
source reports a connection error, the shell has no egress — switch to the
WebFetch path and don't retry the script.
Every source degrades independently. A dead, rate-limited, or key-less source is
a gap you report, not a reason to stop. Collect what you can, then state what you
missed and why. The verdict must reflect the evidence you actually gathered.
Accept files, hashes, and batches
A bare hash is the common case. Normalize it: strip whitespace and any
sha256: / 0x prefix, lowercase the hex. Classify by length — 32 hex chars is
MD5, 40 is SHA-1, 64 is SHA-256. All three are valid lookup keys; SHA-256 is
preferred because it is collision-resistant and every source keys on it. If the
string is not valid hex of one of those lengths, say so instead of guessing.
A file — uploaded or named by path — means the user wants you to identify
what they have. Compute all three digests before looking anything up; the script
does this automatically when handed a path, or run
python3 scripts/hashcheck.py /path/to/file. Report the SHA-256 you computed so
the user can confirm it matches their file. Never execute the file to inspect it.
Multiple hashes in one request means triage a set. Run each through the same
workflow, but keep each write-up tight — lead with a one-line summary table
(hash, verdict, family) so the analyst can scan the batch, then give the full
briefing only for the ones that warrant it. Don't produce five identical
full-length reports for five clean files.
Workflow
1. Identify the file
From the sources, establish what the file is before judging it: file type and
"magic" (PE, ELF, Mach-O, PDF, Office, script, archive), size, common names it
has been seen under, and first-seen date. VirusTotal's type_description,
meaningful_name, names[], size, and first_submission_date cover this;
MalwareBazaar's file_type, file_name, and first_seen corroborate. A recent
first-seen date on a file already carrying detections suggests a fresh campaign.
2. Read the detection consensus
This is the headline. From VirusTotal, read last_analysis_stats
(malicious / suspicious / undetected / harmless) for the score, and
last_analysis_results{} for what engines call it. Name two or three reputable
engines (Microsoft, Kaspersky, ESET-NOD32, Malwarebytes) and the family they
assign rather than listing all ~70. popular_threat_classification.suggested_ threat_label gives VirusTotal's rolled-up family guess — quote it when present.
On the WebFetch path, the v2 file/report endpoint gives positives/total
and per-engine scans{} instead; read the same signal from those.
Interpret honestly. Ten engines agreeing on "Trojan:Win32/Wacatac" is a
conviction. Two engines with generic "ML.Attribute.HighConfidence" or
"gen:variant" labels on a file nothing else flags is a lead to verify, not a
verdict. Say which situation you are in.
3. Check code-signing and provenance
Pull the digital signature. VirusTotal signature_info carries verified
(the plain-English status — "Signed", "Invalid signature", "This file is not
signed"), subject / signers (who signed it), product and description,
and the signing/counter-signing dates. MalwareBazaar's code_sign[] gives the
certificate subject_cn, issuer_cn, valid_from / valid_to, and
thumbprint.
Judge four things and say what each means:
- Signed vs. unsigned. Unsigned is normal for scripts and open-source
tools, unremarkable on its own, but removes a trust anchor for a Windows
binary that would normally ship signed.
- Verification status. "Signed" and verified is reassuring. "Invalid",
"expired", "revoked", or "unverifiable" is a red flag — a tampered or spoofed
signature is worse than none, because it is an attempt to borrow trust.
- Who signed it. A signer that matches the software's claimed publisher
(Microsoft, Google, a known vendor) supports legitimacy. A signer that is a
random company, a mismatched name, or a recently-issued certificate on a
suspicious file is a strong negative — stolen and abused code-signing
certificates are a known attacker technique.
- Certificate age and validity window. A certificate issued days before the
file first appeared, or one already expired at signing time, deserves scrutiny.
4. Examine file structure (PE sections and entropy)
For Windows PE files, read VirusTotal pe_info: sections[] (each with name,
virtual_address, raw_size, and entropy), imphash, import_list[]
(the DLLs and APIs it pulls in), entry_point, and any resource_details.
What to look for and why:
- High section entropy (above ~7.2 on a 0–8 scale) means the section is
compressed or encrypted. Packers (UPX, Themida, ASPack) and malware droppers
do this to hide code from static scanners. Legitimate installers pack too, so
treat high entropy as a flag that raises the bar for a "benign" call, not as
proof of malice.
- Telltale section names —
UPX0/UPX1, .themida, .aspack, .vmp0,
or random-looking names — name the packer outright.
- A minimal import table (a handful of APIs, often just
LoadLibrary /
GetProcAddress) is classic for a packed stub that unpacks the real payload at
runtime. A rich, coherent import set is more consistent with normal software.
- Type/extension mismatch — a file served as
invoice.pdf whose magic says
PE executable — is itself a finding worth leading with.
On the WebFetch path you will usually not have pe_info. Note that section and
entropy analysis was unavailable rather than omitting the topic silently.
5. Pull sandbox behavior and corroboration
When static signals are ambiguous or the user is investigating an active
incident, add dynamic and community evidence:
- Hybrid Analysis (
/api/v2/search/hash) returns verdict,
threat_score, vx_family, and mitre_attcks[] — behavior mapped to the
MITRE ATT&CK framework (a catalog of adversary techniques). Read the verdict
and the top techniques.
- Joe Sandbox search returns analyses with a maliciousness score and
detection; report the score and whether it flagged the sample.
- VirusTotal
sandbox_verdicts{}, crowdsourced_yara_results[] (named
detection rules that matched — often carry a precise family), and
sigma_analysis_results[] (suspicious-behavior log rules) add behavioral
weight without a separate sandbox call.
- MalwareBazaar
vendor_intel{}, tags[], and delivery_method tell you
how the sample is distributed (spam attachment, drive-by, etc.).
WebSearch the raw hash, e.g. "44d88612fea8a8f36de82e1278abb02f" malware, to surface vendor writeups, sandbox reports, and blocklist entries.
Rely on it entirely when no API keys are set.
Distinguish what the file is from what merely mentions it. A blog that
lists a hash in a table of indicators is corroboration; it is not independent
analysis. Prefer engine detections, signing facts, and sandbox verdicts over
raw search-hit counts.
Write the summary in Google technical writing style
The summary is the part an analyst actually reads. Follow Google's technical
writing standards, because they produce prose a reader scans quickly and cannot
misread:
- State the conclusion first. Open with what the file is and the risk call.
Don't build to it.
- Use active voice and present tense. Write "Microsoft flags this as
Wacatac," not "this is flagged as Wacatac by Microsoft."
- Keep sentences short. One idea per sentence. Aim under 25 words.
- Address the reader as "you." Write "quarantine this on your endpoints,"
not "one might consider quarantining it."
- Define terms and expand abbreviations on first use. Write "imphash (import
hash, a fingerprint of the file's import table)."
- Cut filler. Delete "basically," "very," "it should be noted that," and "in
order to." Replace vague words with specific ones.
- Avoid ambiguous pronouns. Write "this certificate," not "this."
- Never hedge to sound safe. If the data is thin, say which data is missing.
Hold the summary to one paragraph of three to five sentences. Be technical
and concrete: name the family, the engine count, the signer, the packer, the
entropy. Prefer a specific fact over an adjective. An analyst triaging a queue
reads the verdict and the summary; everything else is reference. If a sentence
doesn't change what the reader does next, cut it.
Before (verbose, passive, hedged):
It should be noted that this file appears to possibly be detected by a number
of different antivirus engines, and it seems that it may have been packed using
some kind of packing software, which is often associated with malware.
After (Google style):
This is AgentTesla, an info-stealer. 58 of 72 engines flag it, with Microsoft,
ESET, and Kaspersky agreeing on the family. The file is an unsigned Windows PE
packed with UPX (its .UPX1 section reads 7.9 entropy) and imports only
LoadLibrary/GetProcAddress — a classic unpack-at-runtime stub. Quarantine
it and hunt for the %AppData% drop it creates.
Output format
Produce these parts in this order. Lead with the verdict, because an analyst
reads top-down and wants the conclusion first.
## hashcheck: <sha256 or the hash given> — Verdict: <Benign | Suspicious | Malicious | Unknown>
<Three to five sentences in Google technical writing style. What the file is,
its detection consensus, its signing and structure, and why you assigned that
verdict.>
### Facts
| Field | Value |
|---|---|
| Hash (query) | <the hash the user gave, with its type> |
| SHA-256 | |
| SHA-1 | |
| MD5 | |
| File type | <PE32 exe, ELF, PDF, Office macro, script, ...> |
| File size | |
| Common names | <names it has been seen under> |
| First seen | <date> |
| Detections | <e.g. 58/72 malicious; or "0/70"; or "not in any database"> |
| Threat label | <VT suggested_threat_label / agreed family> |
| Notable engines | <2–3 reputable engines and what they call it> |
| Signature | <Signed by <signer>, verified; or Unsigned; or Invalid/Expired/Revoked> |
| Signing cert | <issuer, validity window; omit if unsigned> |
| Packing / entropy | <packer name and/or high-entropy sections, or "no packing indicators"> |
| Imphash | |
| Sandbox verdict | <Hybrid Analysis / Joe Sandbox score and behavior, or "not reached"> |
| YARA / Sigma | <named rule matches, or omit> |
| MITRE ATT&CK | <top techniques observed, or omit> |
| Distribution | <delivery method / tags, or omit> |
| Sources reached | <list; name any that failed or lacked a key> |
### Notes
<Up to five short bullets. Caveats, gaps, or leads worth a human's follow-up.
Omit this section if there are none.>
Include a row only when you have a value or a meaningful "not reached" for it.
Keep a row when its emptiness is informative, such as "Detections: not in any
database (file unknown to all sources)." Drop signing/PE rows entirely for file
types where they don't apply (a PDF has no pe_info; a shell script has no
signature).
Keep Notes to five bullets at most, and put only decision-relevant material
there — a caveat that changes how to read a fact, a gap that limits confidence,
or a lead worth chasing. Notes are not a place to restate the table or narrate
your process.
For a batch, print a one-line summary table first:
| Hash (short) | Verdict | Family / note |
|---|---|---|
| 44d88612… | Malicious | AgentTesla, 58/72 |
| a1b2c3d4… | Benign | Signed Microsoft, 0/72 |
Then give the full briefing only for hashes that are Suspicious, Malicious, or
that the user should look at closely.
Assign the verdict
The verdict is a judgment call, not a formula. Explain your reasoning in the
summary so a human can disagree. Use exactly one of Benign, Suspicious,
Malicious, or Unknown in the header. Don't qualify it, hyphenate it, or
invent a compound label — downstream readers and tooling key off that single
word.
Malicious — a meaningful count of reputable engines agree it is
malware, especially with a consistent family name; or a sandbox reports
malicious behavior; or the file combines strong structural red flags (packing,
a spoofed or revoked signature, type/extension mismatch) with any detections.
Suspicious — the picture is mixed or concerning but not conclusive: a
few detections without consensus, heavy packing or high entropy on an unsigned
binary with no clean provenance, a broken or mismatched signature, or a file
that behaves oddly in a sandbox but engines haven't caught up. Also use this
when data is partial enough to leave real doubt — "Suspicious — limited data"
tells the analyst to look closer.
Benign — zero or only trivial generic detections, and where applicable a
valid signature from a named reputable vendor and an unremarkable structure.
A widely-seen, long-known file with clean results across sources earns this.
Say "no negative reputation found across ," not "clean," and name the
sources.
Unknown — no source has a record of the hash and you can't compute
structure (e.g. you have only the hash, not the file). This is common and
honest. Don't upgrade it to Benign; an unseen file is unproven, not safe.
Tell the user that submitting the file itself (which hashcheck won't do
automatically) would resolve it.
A clean, signed file can still do something the user should think twice about —
a legitimate remote-access tool, say. The verdict rates the file's
maliciousness; if there's a separate "legitimate but risky" angle, put it in
the summary's last sentence or the first Note and keep the header word clean.
When data is thin, don't overclaim. State what would change your assessment —
"if you can share the file, submitting it to VirusTotal would confirm."
Reference
Read references/sources.md for the full endpoint catalog, authentication
details, exact response fields, environment-variable names, and per-source
failure behavior. Consult it when a lookup returns something unfamiliar, you need
an alternate source, or you're wiring up which keys are present.
1---2name: hashcheck3description: Run an open-source intelligence (OSINT) investigation on a single file hash (MD5, SHA-1, or SHA-256) and return a malware analyst's briefing: a risk verdict, a short technical summary, and a facts table. Weighs multi-engine detections, code-signing status, and file structure (PE sections, entropy) heavily. Use this whenever the user types "hashcheck" followed by a hash, and also whenever they paste a hash or point at a file and ask you to "investigate", "look up", "check the reputation of", "analyze", "run OSINT on", "is this file safe", "is this malware", "what is this file", or "should I trust this binary" — even if they don't say the word "hashcheck". Trigger on bare hashes like 44d88612fea8a8f36de82e1278abb02f, on a file the user uploads or names, and on requests to triage a suspicious download, attachment, or sample. This is passive, defensive reconnaissance only.4---5 6# hashcheck7 8Investigate one file — identified by its hash — and give a malware analyst a9briefing they can act on in under a minute. If the user gives you a file instead10of a hash, compute its SHA-256 first (see "Accept files and batches"). A verdict11of benign, suspicious, or malicious is the point; get there and justify it.12 13Don't dump raw API output. Synthesize. Pull detections, code-signing, file14structure, and sandbox behavior into one picture, then make a defensible call15about how much to worry.16 17This is **passive reconnaissance**. You look up what public malware databases18already know about a hash. You never detonate the sample, download and run it,19submit it anywhere without saying so, or reach out to attacker infrastructure.20The hash is a fingerprint; treat this as a records check on that fingerprint. If21a user asks hashcheck to execute or actively probe a sample, decline that part22and explain that hashcheck is read-only.23 24## What the verdict rests on25 26A hash lookup answers four questions. Weight them in this order.27 281. **Consensus detection.** How many reputable engines flag this file, and what29 do they call it? A high, consistent detection count with an agreed family30 name (e.g. "Emotet", "AgentTesla") is the strongest single signal. A handful31 of generic "heuristic" or "ML" hits on an otherwise clean file is weak.322. **Code-signing and provenance.** A file signed by a named, reputable vendor33 with a currently-valid certificate that VirusTotal verifies is far more34 trustworthy than an unsigned one. A *broken*, *expired*, *revoked*, or35 *mismatched* signature is worse than no signature at all, because it signals36 tampering or impersonation. Read who signed it, not just whether it is signed.373. **File structure.** For Windows PE files, section entropy and layout betray38 packing and obfuscation. A section with entropy above ~7.2 is likely packed39 or encrypted — common in malware, but also in legitimate installers, so it is40 a flag, not a conviction. An unusual section name (`.UPX0`, `.themida`), a41 tiny import table, or a mismatch between the file type and its extension all42 deserve a mention.434. **Sandbox behavior and corroboration.** Dynamic-analysis verdicts, dropped44 files, network indicators, and YARA/Sigma matches turn "some engines flag it"45 into "here is what it does." Reach for these when the static picture is46 ambiguous or the user is working an active incident.47Absence of evidence is not evidence of safety. A hash no database has seen is48**unknown**, not clean — say so, and lean on structure and signing to reason49about it.50 51## Network access: pick the working path first52 53hashcheck depends on reaching public malware-intel APIs. How you reach them54varies by environment, and choosing wrong produces a page of connection errors55instead of a report.56 571. **The bundled script** `scripts/hashcheck.py`. This runs every lookup at once58 and prints a single compact JSON object. It works where the **shell has59 internet and the API keys are set as environment variables**, such as Claude60 Code on a workstation. It queries the richer, authenticated endpoints —61 VirusTotal **v3** (`pe_info`, `signature_info`, sandbox verdicts),62 MalwareBazaar, Hybrid Analysis, and Joe Sandbox — that need custom headers63 the WebFetch tool cannot send. Prefer this path whenever a shell with egress64 exists: `python3 scripts/hashcheck.py <hash-or-file>`.652. **The WebFetch tool** (`mcp__workspace__web_fetch` or `WebFetch`) plus66 `WebSearch`. Use this in Cowork and other sandboxes where the shell has no67 outbound internet. WebFetch can only issue GET requests and cannot set the68 `Auth-Key`, `x-apikey`, or `api-key` headers the deep endpoints require, so on69 this path you get **VirusTotal's v2 endpoint** (which accepts the key as a70 query parameter) for the multi-engine verdict, plus `WebSearch` for71 corroboration. You will usually not get PE sections, entropy, or signing72 detail on this path — say so in the report rather than inventing it.73Try the script first when a shell exists. If its output contains74`Tunnel connection failed`, `network unreachable`, `name resolution`, or every75source reports a connection error, the shell has no egress — switch to the76WebFetch path and don't retry the script.77 78Every source degrades independently. A dead, rate-limited, or key-less source is79a gap you report, not a reason to stop. Collect what you can, then state what you80missed and why. The verdict must reflect the evidence you actually gathered.81 82## Accept files, hashes, and batches83 84**A bare hash** is the common case. Normalize it: strip whitespace and any85`sha256:` / `0x` prefix, lowercase the hex. Classify by length — 32 hex chars is86MD5, 40 is SHA-1, 64 is SHA-256. All three are valid lookup keys; SHA-256 is87preferred because it is collision-resistant and every source keys on it. If the88string is not valid hex of one of those lengths, say so instead of guessing.89 90**A file** — uploaded or named by path — means the user wants you to identify91what they have. Compute all three digests before looking anything up; the script92does this automatically when handed a path, or run93`python3 scripts/hashcheck.py /path/to/file`. Report the SHA-256 you computed so94the user can confirm it matches their file. Never execute the file to inspect it.95 96**Multiple hashes** in one request means triage a set. Run each through the same97workflow, but keep each write-up tight — lead with a one-line summary table98(hash, verdict, family) so the analyst can scan the batch, then give the full99briefing only for the ones that warrant it. Don't produce five identical100full-length reports for five clean files.101 102## Workflow103 104### 1. Identify the file105 106From the sources, establish what the file *is* before judging it: file type and107"magic" (PE, ELF, Mach-O, PDF, Office, script, archive), size, common names it108has been seen under, and first-seen date. VirusTotal's `type_description`,109`meaningful_name`, `names[]`, `size`, and `first_submission_date` cover this;110MalwareBazaar's `file_type`, `file_name`, and `first_seen` corroborate. A recent111first-seen date on a file already carrying detections suggests a fresh campaign.112 113### 2. Read the detection consensus114 115This is the headline. From VirusTotal, read `last_analysis_stats`116(`malicious` / `suspicious` / `undetected` / `harmless`) for the score, and117`last_analysis_results{}` for *what* engines call it. Name two or three reputable118engines (Microsoft, Kaspersky, ESET-NOD32, Malwarebytes) and the family they119assign rather than listing all ~70. `popular_threat_classification.suggested_120threat_label` gives VirusTotal's rolled-up family guess — quote it when present.121 122On the WebFetch path, the v2 `file/report` endpoint gives `positives`/`total`123and per-engine `scans{}` instead; read the same signal from those.124 125Interpret honestly. Ten engines agreeing on "Trojan:Win32/Wacatac" is a126conviction. Two engines with generic "ML.Attribute.HighConfidence" or127"gen:variant" labels on a file nothing else flags is a lead to verify, not a128verdict. Say which situation you are in.129 130### 3. Check code-signing and provenance131 132Pull the digital signature. VirusTotal `signature_info` carries `verified`133(the plain-English status — "Signed", "Invalid signature", "This file is not134signed"), `subject` / `signers` (who signed it), `product` and `description`,135and the signing/counter-signing dates. MalwareBazaar's `code_sign[]` gives the136certificate `subject_cn`, `issuer_cn`, `valid_from` / `valid_to`, and137`thumbprint`.138 139Judge four things and say what each means:140 141- **Signed vs. unsigned.** Unsigned is normal for scripts and open-source142 tools, unremarkable on its own, but removes a trust anchor for a Windows143 binary that would normally ship signed.144- **Verification status.** "Signed" and verified is reassuring. "Invalid",145 "expired", "revoked", or "unverifiable" is a red flag — a tampered or spoofed146 signature is worse than none, because it is an attempt to borrow trust.147- **Who signed it.** A signer that matches the software's claimed publisher148 (Microsoft, Google, a known vendor) supports legitimacy. A signer that is a149 random company, a mismatched name, or a recently-issued certificate on a150 suspicious file is a strong negative — stolen and abused code-signing151 certificates are a known attacker technique.152- **Certificate age and validity window.** A certificate issued days before the153 file first appeared, or one already expired at signing time, deserves scrutiny.154### 4. Examine file structure (PE sections and entropy)155 156For Windows PE files, read VirusTotal `pe_info`: `sections[]` (each with `name`,157`virtual_address`, `raw_size`, and `entropy`), `imphash`, `import_list[]`158(the DLLs and APIs it pulls in), `entry_point`, and any `resource_details`.159 160What to look for and why:161 162- **High section entropy** (above ~7.2 on a 0–8 scale) means the section is163 compressed or encrypted. Packers (UPX, Themida, ASPack) and malware droppers164 do this to hide code from static scanners. Legitimate installers pack too, so165 treat high entropy as a flag that raises the bar for a "benign" call, not as166 proof of malice.167- **Telltale section names** — `UPX0`/`UPX1`, `.themida`, `.aspack`, `.vmp0`,168 or random-looking names — name the packer outright.169- **A minimal import table** (a handful of APIs, often just `LoadLibrary` /170 `GetProcAddress`) is classic for a packed stub that unpacks the real payload at171 runtime. A rich, coherent import set is more consistent with normal software.172- **Type/extension mismatch** — a file served as `invoice.pdf` whose magic says173 PE executable — is itself a finding worth leading with.174On the WebFetch path you will usually not have `pe_info`. Note that section and175entropy analysis was unavailable rather than omitting the topic silently.176 177### 5. Pull sandbox behavior and corroboration178 179When static signals are ambiguous or the user is investigating an active180incident, add dynamic and community evidence:181 182- **Hybrid Analysis** (`/api/v2/search/hash`) returns `verdict`,183 `threat_score`, `vx_family`, and `mitre_attcks[]` — behavior mapped to the184 MITRE ATT&CK framework (a catalog of adversary techniques). Read the verdict185 and the top techniques.186- **Joe Sandbox** search returns analyses with a maliciousness score and187 detection; report the score and whether it flagged the sample.188- **VirusTotal** `sandbox_verdicts{}`, `crowdsourced_yara_results[]` (named189 detection rules that matched — often carry a precise family), and190 `sigma_analysis_results[]` (suspicious-behavior log rules) add behavioral191 weight without a separate sandbox call.192- **MalwareBazaar** `vendor_intel{}`, `tags[]`, and `delivery_method` tell you193 how the sample is distributed (spam attachment, drive-by, etc.).194- **`WebSearch`** the raw hash, e.g. `"44d88612fea8a8f36de82e1278abb02f"195 malware`, to surface vendor writeups, sandbox reports, and blocklist entries.196 Rely on it entirely when no API keys are set.197Distinguish **what the file is** from **what merely mentions it**. A blog that198lists a hash in a table of indicators is corroboration; it is not independent199analysis. Prefer engine detections, signing facts, and sandbox verdicts over200raw search-hit counts.201 202## Write the summary in Google technical writing style203 204The summary is the part an analyst actually reads. Follow Google's technical205writing standards, because they produce prose a reader scans quickly and cannot206misread:207 208- **State the conclusion first.** Open with what the file is and the risk call.209 Don't build to it.210- **Use active voice and present tense.** Write "Microsoft flags this as211 Wacatac," not "this is flagged as Wacatac by Microsoft."212- **Keep sentences short.** One idea per sentence. Aim under 25 words.213- **Address the reader as "you."** Write "quarantine this on your endpoints,"214 not "one might consider quarantining it."215- **Define terms and expand abbreviations on first use.** Write "imphash (import216 hash, a fingerprint of the file's import table)."217- **Cut filler.** Delete "basically," "very," "it should be noted that," and "in218 order to." Replace vague words with specific ones.219- **Avoid ambiguous pronouns.** Write "this certificate," not "this."220- **Never hedge to sound safe.** If the data is thin, say which data is missing.221Hold the summary to **one paragraph of three to five sentences**. Be technical222and concrete: name the family, the engine count, the signer, the packer, the223entropy. Prefer a specific fact over an adjective. An analyst triaging a queue224reads the verdict and the summary; everything else is reference. If a sentence225doesn't change what the reader does next, cut it.226 227**Before (verbose, passive, hedged):**228> It should be noted that this file appears to possibly be detected by a number229> of different antivirus engines, and it seems that it may have been packed using230> some kind of packing software, which is often associated with malware.231 232**After (Google style):**233> This is AgentTesla, an info-stealer. 58 of 72 engines flag it, with Microsoft,234> ESET, and Kaspersky agreeing on the family. The file is an unsigned Windows PE235> packed with UPX (its `.UPX1` section reads 7.9 entropy) and imports only236> `LoadLibrary`/`GetProcAddress` — a classic unpack-at-runtime stub. Quarantine237> it and hunt for the `%AppData%` drop it creates.238 239## Output format240 241Produce these parts in this order. Lead with the verdict, because an analyst242reads top-down and wants the conclusion first.243 244```245## hashcheck: <sha256 or the hash given> — Verdict: <Benign | Suspicious | Malicious | Unknown>246 247<Three to five sentences in Google technical writing style. What the file is,248its detection consensus, its signing and structure, and why you assigned that249verdict.>250 251### Facts252| Field | Value |253|---|---|254| Hash (query) | <the hash the user gave, with its type> |255| SHA-256 | |256| SHA-1 | |257| MD5 | |258| File type | <PE32 exe, ELF, PDF, Office macro, script, ...> |259| File size | |260| Common names | <names it has been seen under> |261| First seen | <date> |262| Detections | <e.g. 58/72 malicious; or "0/70"; or "not in any database"> |263| Threat label | <VT suggested_threat_label / agreed family> |264| Notable engines | <2–3 reputable engines and what they call it> |265| Signature | <Signed by <signer>, verified; or Unsigned; or Invalid/Expired/Revoked> |266| Signing cert | <issuer, validity window; omit if unsigned> |267| Packing / entropy | <packer name and/or high-entropy sections, or "no packing indicators"> |268| Imphash | |269| Sandbox verdict | <Hybrid Analysis / Joe Sandbox score and behavior, or "not reached"> |270| YARA / Sigma | <named rule matches, or omit> |271| MITRE ATT&CK | <top techniques observed, or omit> |272| Distribution | <delivery method / tags, or omit> |273| Sources reached | <list; name any that failed or lacked a key> |274 275### Notes276<Up to five short bullets. Caveats, gaps, or leads worth a human's follow-up.277Omit this section if there are none.>278```279 280Include a row only when you have a value or a meaningful "not reached" for it.281Keep a row when its emptiness is informative, such as "Detections: not in any282database (file unknown to all sources)." Drop signing/PE rows entirely for file283types where they don't apply (a PDF has no `pe_info`; a shell script has no284signature).285 286Keep Notes to five bullets at most, and put only decision-relevant material287there — a caveat that changes how to read a fact, a gap that limits confidence,288or a lead worth chasing. Notes are not a place to restate the table or narrate289your process.290 291For a **batch**, print a one-line summary table first:292 293```294| Hash (short) | Verdict | Family / note |295|---|---|---|296| 44d88612… | Malicious | AgentTesla, 58/72 |297| a1b2c3d4… | Benign | Signed Microsoft, 0/72 |298```299 300Then give the full briefing only for hashes that are Suspicious, Malicious, or301that the user should look at closely.302 303## Assign the verdict304 305The verdict is a judgment call, not a formula. Explain your reasoning in the306summary so a human can disagree. **Use exactly one of `Benign`, `Suspicious`,307`Malicious`, or `Unknown` in the header.** Don't qualify it, hyphenate it, or308invent a compound label — downstream readers and tooling key off that single309word.310 311- **`Malicious`** — a meaningful count of reputable engines agree it is312 malware, especially with a consistent family name; or a sandbox reports313 malicious behavior; or the file combines strong structural red flags (packing,314 a spoofed or revoked signature, type/extension mismatch) with any detections.315- **`Suspicious`** — the picture is mixed or concerning but not conclusive: a316 few detections without consensus, heavy packing or high entropy on an unsigned317 binary with no clean provenance, a broken or mismatched signature, or a file318 that behaves oddly in a sandbox but engines haven't caught up. Also use this319 when data is partial enough to leave real doubt — "Suspicious — limited data"320 tells the analyst to look closer.321- **`Benign`** — zero or only trivial generic detections, and where applicable a322 valid signature from a named reputable vendor and an unremarkable structure.323 A widely-seen, long-known file with clean results across sources earns this.324 Say "no negative reputation found across <sources>," not "clean," and name the325 sources.326- **`Unknown`** — no source has a record of the hash and you can't compute327 structure (e.g. you have only the hash, not the file). This is common and328 honest. Don't upgrade it to Benign; an unseen file is unproven, not safe.329 Tell the user that submitting the file itself (which hashcheck won't do330 automatically) would resolve it.331A clean, signed file can still do something the user should think twice about —332a legitimate remote-access tool, say. The verdict rates **the file's333maliciousness**; if there's a separate "legitimate but risky" angle, put it in334the summary's last sentence or the first Note and keep the header word clean.335 336When data is thin, don't overclaim. State what would change your assessment —337"if you can share the file, submitting it to VirusTotal would confirm."338 339## Reference340 341Read `references/sources.md` for the full endpoint catalog, authentication342details, exact response fields, environment-variable names, and per-source343failure behavior. Consult it when a lookup returns something unfamiliar, you need344an alternate source, or you're wiring up which keys are present.