Antivirus testing
EICAR Test File: How to Test an Antivirus API Without Real Malware
What the EICAR test file is, why antivirus APIs rely on it, and how to scan it with Threatless to prove malware detection without handling a real sample.
- EICAR
- Antivirus API
- ClamAV
- CI
If you are wiring malware scanning into an upload API, a CI job, or a partner integration, you need a known positive. Production malware is the wrong tool for that job. It is dangerous to store, awkward to email, and often forbidden by policy.
The EICAR test file exists so you can prove a scanner still detects threats without ever handling a real sample. This guide explains what EICAR is, what it is not, how to obtain it only from the official source, and how to use it with the Threatless Scan API. For the short operator checklist, use the docs page Test with EICAR.
What the EICAR test file is
EICAR stands for the European Institute for Computer Antivirus Research. In the mid-1990s the group published a tiny, documented test file so antivirus vendors could share one expected positive across engines, gateways, and desktop products.
The file is a short ASCII sample. Antivirus engines, including ClamAV, ship a signature that matches it. When a scanner reports that signature, you know the engine loaded definitions, accepted the bytes, and took the detection path — not that you found a campaign in the wild.
Useful properties of the official file:
- It is harmless. It is not an exploit, dropper, or self-replicating program.
- It is small (the standard COM-style sample is 68 bytes), so it is cheap to upload in tests.
- It is documented. Vendors agree on the intent even when the exact signature name differs slightly between engines.
- It is distributed by eicar.org in several formats (plain test file, zip archives, and related variants) so you can also exercise archive handling.
A non-functional illustration of the shape — not the official payload — looks like this:
[official prefix omitted]…EICAR-STANDARD-ANTIVIRUS-TEST-FILE…[official suffix omitted]
That snippet is intentionally incomplete. Do not try to reconstruct the official string from memory. If you need a real positive, download it from eicar.org.
What EICAR is not
Teams get into trouble when they treat EICAR as something it is not.
It is not a virus. It does not infect hosts, encrypt disks, or phone home. A detection is a signature match against a published test pattern.
It is not a substitute for a malware zoo. EICAR proves the scanner’s positive path for one well-known sample. It does not prove coverage of ransomware families, macros, or packed binaries. Use it as a canary, then rely on ClamAV’s signature set — and your own threat model — for breadth.
It is not a clean-file test. Scanning a README only proves the happy path (infected: false). You still need EICAR (or another known positive) to prove infected: true.
It is not safe to copy-paste everywhere. The payload is inert, but security products will still alert on it. That is the point of the test, and it is why this article never prints the official string.
It is not a reason to send real malware to a hosted API. If EICAR does not detect, fix the download, the filename, or the request. Do not “escalate” to a live sample against api.trythreatless.com.
Why the test file exists
Antivirus products used to be validated with live samples. That does not scale for SaaS APIs, CI, or customer onboarding:
- Storing malware creates legal, HR, and incident-response overhead.
- Emailing samples to contact@trythreatless.com will be rejected or quarantined.
- Git hosts may block the commit, then every clone of the repo becomes an alert factory.
- Reviewers cannot tell a missed detection from a broken fixture if the fixture itself is contraband.
EICAR gives vendors and customers a shared, policy-friendly positive. A new API key can be verified end-to-end. A CI job can assert that last week’s engine update did not silently disable detection. A security review can see a known-good infected: true without standing up a malware lab.
Why security and API vendors use it
If you sell or consume a malware scanning API, you need both verdicts:
| Path | Fixture | Expected JSON |
|---|---|---|
| Clean | Any small text file you created | infected: false, virusName: null |
| Detected | Official EICAR from eicar.org | infected: true, a ClamAV EICAR signature name |
Vendors use EICAR because:
- Onboarding is deterministic. A customer can prove the key, the endpoint, and the parser without waiting for a real upload to be malicious.
- Regressions are obvious. If a deploy returns
infected: falsefor official EICAR, the pipeline should fail before production traffic does. - Support stays safe. You can ask a customer to scan EICAR instead of asking them to mail a sample.
- Quota and latency tests stay honest. The 68-byte file still consumes one hourly scan unit and still exercises streaming, ClamAV, and JSON serialization.
Threatless is built around that contract: POST /api/v1/scans, X-API-KEY, in-memory ClamAV, JSON back. EICAR is the fastest way to see the infected half of that contract. Read Scanning if you need the engine and size limits around it.
How to obtain EICAR safely
- Open the official download page: eicar.org/download-anti-malware-testfile.
- Download a format your tests actually need. The plain test file is enough for a multipart upload. Zip variants are useful only when you intend to scan an archive.
- Save it on a machine where AV test files are allowed. Endpoint agents may quarantine it on arrival — that is expected.
- Do not commit it. Add the filename to
.gitignoreif it lands in a working tree. - Do not fetch random mirrors, GitHub gists, or “eicar generator” pages. Those copies are often truncated, HTML error pages, or unrelated files that will produce
infected: falseand a wasted debugging hour.
Replace eicar.com below with whatever name the official download used. Some browsers save eicar.com.txt. The bytes matter, not the extension.
If your laptop AV deletes the file immediately, download it inside a CI runner, a disposable VM, or a directory excluded from the local agent — still using eicar.org as the only source.
How to use EICAR with Threatless
Create an account, mint a key, then scan the official file. The quickstart covers keys; authentication covers X-API-KEY. Copy-paste clients live in language examples.
curl -X POST https://api.trythreatless.com/api/v1/scans \
-H "X-API-KEY: YOUR_API_KEY" \
-F "file=@./eicar.com"
You can also scan a public HTTP(S) URL that serves the official file, using the url field on the same endpoint. Prefer uploading the file you downloaded yourself so you are not depending on a third-party CDN remaining up, unaltered, and reachable from the scanner. URL fetching blocks private networks and metadata hosts; see Scan a URL.
The dashboard scanner (POST /web/scans) accepts a file from your session if you would rather not put a key in a shell history. Same engine, same verdict, still one quota unit.
Expected result
A successful EICAR detection looks like this (filename, extension, and size follow what you uploaded):
{
"filename": "eicar.com",
"extension": "com",
"sizeInBytes": 68,
"scanDurationMillis": 18,
"infected": true,
"virusName": "Win.Test.EICAR_HDB-1"
}
Read that payload the way your code should:
- HTTP 200 means the scan completed. Infection is a successful result, not an API error.
infectedmust betrue.virusNameis the ClamAV signature string.Win.Test.EICAR_HDB-1is the usual name. Closely related EICAR names can appear if signatures change — assert oninfectedplus an EICAR-ishvirusName, not on a single frozen string, unless you pin engine versions.- The request consumes one hourly quota unit and returns
X-RateLimit-Limit,X-RateLimit-Remaining, andX-RateLimit-Reset. Hitting the ceiling is a 429 withRetry-After, which is unrelated to the verdict. See rate limits.
If you receive infected: false, you almost certainly did not upload the official file. Common causes: a truncated copy, the HTML download page saved as the body, an empty fixture, or a zip you did not intend to scan as a container. Download again from eicar.org. If you did mean to scan a zip, ClamAV may still report EICAR inside it — inspect virusName rather than guessing.
Clean control
Pair every EICAR check with a clean file you created (a tiny readme.txt is enough):
{
"filename": "readme.txt",
"extension": "txt",
"sizeInBytes": 12,
"scanDurationMillis": 15,
"infected": false,
"virusName": null
}
Together, the two requests prove both branches of your if (result.infected) logic.
Best practices
- Source of truth is eicar.org. Treat any other URL as untrusted.
- Keep fixtures out of git. Document the download step in README or CI. If a teammate needs the file, point them at the official page.
- Assert behavior, not folklore. Require HTTP 200,
infected: true, and a non-nullvirusNamethat refers to EICAR. Do not parse logs for the official ASCII payload. - Watch the filename you send. The API requires a non-empty original filename on multipart uploads. A missing
filename=in the form part fails validation before ClamAV runs. See Scan a file. - Stay under 10 MB. EICAR will never hit this; your production uploads might. Fail closed when the API returns a size error.
- Quota is per clock hour. A chatty test suite can burn the Free plan (5 scans/hour) before lunch. Cache the EICAR result in unit tests; hit the live API in a small integration job.
- Privacy still applies. Threatless does not persist file bytes after the scan. Metadata (filename, size, verdict, timestamps) remains in your history. EICAR does not change that model — see privacy in the product and the Privacy Policy.
- Self-hosting needs a healthy
clamd. If you run Threatless with Docker, EICAR is the fastest check that the bundled ClamAV container is reachable and loaded signatures.
Using EICAR in CI
Threatless has no GitHub App. CI is the Scan API plus a secret. The CI / GitHub Actions doc shows a job that scans a build artifact. Extend that pattern with a second job or step that scans official EICAR.
A robust layout:
- Store
THREATLESS_API_KEYas a repository secret. Never log it. - In the job, download EICAR from eicar.org into the runner workspace (or restore a cached copy you obtained the same way).
POSTthe file tohttps://api.trythreatless.com/api/v1/scans.- Fail the job unless
infectedis true. - Scan a clean artifact (your actual build) and fail if that is infected.
Do not commit eicar.com to the repo so CI can “just work.” GitHub, GitLab, and local hooks may reject the push, and every developer clone will trip endpoint software.
If the runner’s outbound filter blocks eicar.org, obtain the file through an internal allow-listed mirror that you control and that you refresh from the official source — still without checking the payload into git. If you cannot obtain EICAR in CI at all, run the positive test in a dedicated environment and keep CI on clean artifacts plus contract tests against recorded JSON.
Hourly quota applies in CI the same as in production. A matrix of 20 jobs each scanning EICAR plus a tarball can 429 on small plans. Deduplicate: one EICAR canary per pipeline is enough.
Common mistakes
Pasting the payload into an issue or pull request. Review tools and mail gateways will flag it. Link to eicar.org instead.
Committing a “safe excerpt” that is actually the full string. If a test helper contains the official payload, it is the test file. Keep helpers payload-free, like this article.
Scanning the download HTML. curl without -L, or a browser “Save as” on the wrong node, stores a web page. ClamAV will call it clean. Check sizeInBytes — 68 is the usual size for the standard file; a 20 KB body is not EICAR.
Treating infected: true as an HTTP error. Wrapping the client as if (!response.ok) throw is correct for 4xx/5xx. Wrapping it as if (body.infected) throw at the HTTP helper layer will confuse callers. Keep transport errors and verdicts separate.
Asserting a single virusName forever. Pinning Win.Test.EICAR_HDB-1 is fine in a snapshot test against a pinned engine. In hosted SaaS, prefer infected === true and a virusName that contains EICAR.
Skipping the clean control. A stub client that always returns infected will pass an EICAR-only suite.
Using EICAR as load testing. It is a functional canary, not a throughput benchmark. Use representative file sizes if you care about scanDurationMillis.
Emailing samples to support. Write to contact@trythreatless.com about account or API issues. Attachments that look like malware, including EICAR, are the wrong channel.
What to do next
You now have a safe positive, a clean control, and a JSON contract you can automate on.
- Follow Test with EICAR on your own key.
- Copy a client from language examples.
- Create a Threatless account and run both scans.
- Add the canary to CI using the GitHub Actions guide.
Threatless is the malware scanning API for that workflow: one POST, ClamAV in memory, JSON you can branch on. When the canary stays green, you can trust the detection path for the uploads that actually matter.