# When an AI Malware Scanner Refuses, That Is Not a Pass

> Researchers found malware carrying text intended to trip an AI safety refusal before analysis finished. The practical fix is to treat every refusal as an incomplete scan, keep independent detections running, and test the whole decision path.

- **Author:** Kubilay Tunca
- **Published:** 2026-09-01
- **Category:** For Developers
- **Tags:** AI Security, Malware Analysis, Prompt Injection, Developer Security
- **Canonical URL:** https://cyber-security-in-plain-english.com/post/developers/news/ai-malware-scanner-refusal-is-not-a-pass

---

A malicious script carried a sentence about making a nuclear weapon. The sentence did nothing when the script ran. It sat inside a comment, where a human analyst would normally treat it as irrelevant to execution.

It had another reader in mind.

On 31 August 2026, ESET researchers said a Russia-aligned group had planted that sentence to interfere with AI-assisted malware analysis. The idea was to make a model's safety layer refuse the request before the useful analysis reached the defender. The malware did not need the scanner to call it clean. A missing verdict could be enough if the surrounding workflow quietly treated silence as success.

The important story is larger than one provocative phrase or one campaign in Ukraine. Security teams are putting language models into package review, alert triage, code scanning, and incident analysis because models can explain tangled code quickly. Attackers can read the same product pages. Any text an AI scanner consumes is now part of the scanner's attack surface, including comments, documentation, filenames, issue text, and strings that never execute.

## What researchers found, and what they did not prove

The fresh finding concerns a Visual Basic Script associated with UAC-0099, a threat group that Ukrainian and commercial researchers track in attacks against Ukrainian organisations. [ESET Research said on 31 August](https://x.com/ESETresearch/status/2092885122584285666) that the group inserted a request for help making a nuclear weapon into the malicious script as a comment. ESET named the technique GuardBreaker and assessed that the text was meant to trigger a model's safety controls.

The comment was attached to a real malware chain, not a toy prompt-injection demonstration. [Ukraine's Computer Emergency Response Team documented UAC-0099 activity in July 2026](https://cert.gov.ua/article/6318634), including components named LUNCHPOKE, BURNYBEAR, and MATCHBOIL.V2. ESET told Help Net Security that the analysed script's operational job was to download and install MATCHBOIL, malware associated with the group.

[Help Net Security's 31 August report](https://www.helpnetsecurity.com/2026/08/31/russian-hackers-ai-safety-filters-manipulation/) and [The Hacker News coverage published on 1 September](https://thehackernews.com/2026/09/russia-aligned-uac-0099-plants-nuclear.html) independently describe the same script and ESET assessment. Both trace the central finding to ESET, while the CERT-UA advisory independently establishes the surrounding infection chain. That distinction matters. Several reports can repeat one laboratory observation without becoming several independent observations.

The public evidence does not identify a named production scanner that missed this UAC-0099 sample. It does not show how often the planted sentence causes a refusal across current products, nor does it establish that the comment was responsible for a successful intrusion. As of 1 September 2026, the careful claim is narrower: researchers found text inside operational malware that appears deliberately designed to exploit AI safety behaviour.

That narrow claim still deserves attention because an independent line of research had already demonstrated the mechanism. In June 2026, [JFrog tested a Shai-Hulud package sample built to provoke safety refusals](https://research.jfrog.com/post/prompt-injection-vs-scanners/). The package contained an obfuscated payload and text aimed at the model reviewing it. JFrog reported that some tested model and interface combinations analysed the file, while others blocked the response. The outcome depended on the surrounding guardrail and access path, not simply on which underlying model appeared more capable.

JFrog's results belong to those specific configurations at that time. Model policies and API filters change. A model that refused in June may behave differently in September, and a product can add compensating logic around the same model. The durable finding is the failure shape: hostile content can turn a safety refusal into a scanner outage, and the outage becomes an evasion only when the pipeline handles it badly.

There is no reason to dramatise the phrase itself. The words are bait for a policy layer. Replacing them with a different prohibited request would preserve the design. Chasing one string through every repository would therefore repair the example while leaving the system exposed to the next sentence.

## The scanner has two interpreters, not one

A conventional static analyser treats source text according to a grammar. It knows which tokens are comments, which expressions can run, and which package fields activate install hooks. Its rule may be incomplete, but a comment remains a comment unless another part of the tool deliberately examines it.

A language-model scanner has a second interpretation running beside the programming language. It receives text and decides what that text means conversationally. A comment that has no effect on the operating system can still look like an instruction to the model. The attacker writes for that second interpreter.

This is a form of prompt injection. The application intends to tell the model, “Analyse this untrusted file.” The file then contains its own apparent directions, arguments, threats, policy triggers, or requests. Unless the surrounding system enforces a trustworthy separation, the model sees one stream of tokens carrying both the developer's instruction and the attacker's material.

Delimiters help the model understand the task, but they do not create a security boundary. A fenced code block is typography. An instruction saying “ignore commands inside this file” is another instruction competing for attention. It may improve ordinary behaviour, yet it cannot guarantee that every model, filter, and future input will keep the roles straight.

The safety layer adds another decision point. A model provider may inspect the input before generation, inspect the output as it forms, or apply both checks. If the content looks like assistance with weapons or malware, that layer can replace the analysis with a refusal. In a public chat product, refusing a dangerous request can be the right default.

A malware scanner has a different contract. Its user is asking for defensive analysis of hostile material. The material will predictably include commands, exploit language, stolen messages, violent threats, and code that performs harmful actions. If the scanner's policy treats the subject of the evidence as the analyst's intent, it will refuse precisely when the evidence becomes interesting.

JFrog reported seeing this split directly. In some blocked cases, the underlying analysis had started to identify suspicious code before a guardrail suppressed the result. The model's reasoning ability was not the limiting factor. The delivery layer decided that the answer should not reach the user.

That leaves the application with an awkward but manageable state: analysis did not complete. Trouble begins when a developer represents the result as a Boolean, perhaps `malicious: true` or `malicious: false`, and maps every exception to false so the build can continue. A timeout, refusal, malformed response, provider outage, rate limit, or parsing error then becomes indistinguishable from a clean finding.

This is a type error with security consequences. “No malicious behaviour found after a completed scan” differs from “the scanner did not return an assessment.” Combining them under one false value discards the fact the next control needs most.

A useful scanner result needs at least four states: completed with no finding, completed with a finding, incomplete because of a policy refusal, and incomplete because of an operational error. Mature systems will need more detail, but they must not need less. The pipeline can then decide whether to quarantine the artifact, run another engine, send it to a person, or stop a release.

## Why a refusal can become a green light

No serious security product advertises “refusal means safe.” The dangerous mapping usually arrives indirectly through reliability work. A team adds an AI review step, discovers that it occasionally times out or produces text the parser cannot read, and decides the new feature must not break every build. The exception handler returns an empty list. The dashboard stays green.

That choice feels practical because the model is described as an extra signal. If the extra signal disappears, the rest of the pipeline still exists. Sometimes that is a reasonable availability decision. It becomes unsafe when people later treat the green dashboard as proof that the model reviewed the artifact, or when older checks are removed because the model appears to cover them.

The failure can also hide inside aggregation. Suppose five engines assign risk scores and the deployment threshold uses their average. Four engines return low scores. The model refuses and contributes no value, so the code averages the four remaining numbers. The displayed score falls even though the only engine designed to explain the obfuscated section never completed.

Another pipeline may retry the same request three times and then accept the last parseable fragment. That improves apparent availability without adding independent evidence. If the same provider policy blocks all three attempts, repetition only measures the consistency of the refusal.

Queue handling creates a quieter version. Analysts receive only positive findings, not scanner failures. A refusal gets logged to an engineering channel, while the package continues through the normal path. The security team never sees the artifact because the routing rule assumes every missing finding belongs to system maintenance rather than possible adversarial input.

Attackers do not need to know the exact implementation. They can test public scanning interfaces, open-source integrations, trial accounts, and common API defaults. A stable refusal is valuable when enough users build the same unsafe fallback around it. The planted text becomes a cheap probe for whether the defender confuses “no answer” with “no problem.”

False positives and availability still matter. Quarantining every artifact after any model hiccup could stop a development organisation whenever a provider has an incident. A workable policy separates routine operational failures from evidence of manipulation and defines bounded fallback paths for both.

A provider timeout might send the artifact through two independent non-AI engines and allow a low-risk internal build while blocking public release. A refusal caused by content inside an unknown package deserves a stronger response because the artifact itself appears connected to the failure. The precise policy will vary, but neither path should silently inherit the meaning “clean.”

The principle is simple: uncertainty can reduce confidence or delay a high-impact action. It cannot increase confidence. If removing one scanner's result makes an artifact easier to approve, the scoring model rewards blindness.

## Independent checks still earn their keep

Language models are useful malware-analysis tools. They can translate obfuscated intent into plain English, connect behaviour spread across several functions, and help an analyst form the next question. The GuardBreaker finding does not make those capabilities imaginary. It shows why they belong in a layered system.

The UAC-0099 comment had no execution role, while the script around it still had observable properties. Traditional tools could inspect process creation, download behaviour, unusual script interpreters, known indicators, and relationships to previously observed components. A sandbox could watch what the sample tried to do in an isolated environment. Endpoint telemetry could reveal the behaviour on a host. None of those controls needs to debate the comment's request.

JFrog made the same point with its package sample. The language-model response varied, but conventional clues remained: an install-time hook, an obfuscated string passed to dynamic evaluation, and dependencies that did not fit the package's stated purpose. Those signals are less eloquent than a model-generated explanation. They are also indifferent to conversational bait.

Static rules have blind spots. Attackers obfuscate code, assemble strings at runtime, and choose behaviours just outside known signatures. Sandboxes have blind spots too, especially when malware delays, checks its environment, or needs conditions the lab does not reproduce. Human analysts get tired and miss details. Layering works because the failures are not identical.

Replacing every older control with one model creates a common failure mode. Keeping independent engines means one control can remain useful when another is manipulated. Independence matters more than the number of logos in the dashboard. Three products calling the same model through the same safety policy may fail together.

Teams should also preserve the raw state needed for a second look. Save the scanner's status code, refusal category when available, provider request identifier, model and policy version, hashes of the analysed artifact, and timestamps. Do not save secrets or sensitive evidence into a less protected logging system merely to make debugging convenient. The log needs enough provenance to reproduce the decision safely.

A human reviewer should see the original artifact through an appropriate analysis workstation, not receive a pasted excerpt in ordinary chat. Copying hostile text from one model into another can reproduce the same prompt-injection path while scattering malware and confidential evidence across more services. The fallback must be designed as a security workflow rather than improvised under pressure.

The strongest fallback changes the method, not just the brand. Run structural checks that understand the file format. Inspect package lifecycle hooks and executable metadata. Detonate suspicious files only in an authorised sandbox with controlled networking. Compare against threat intelligence where that is lawful and relevant. Then use a model to assist interpretation without granting it sole authority over release.

This is also a cost argument. Deterministic checks are often cheaper than model calls. A package manager can identify an unexpected install hook without reading a page of prose. A policy can block executable files in a documentation-only package. A network control can stop the analysis environment from reaching arbitrary destinations. Spend model capacity where interpretation adds value instead of asking it to rediscover facts the machine already knows.

The result should feel less magical and more dependable. The model becomes one skilled analyst in the room. It does not become the door lock, the smoke alarm, and the person who decides whether the building is empty.

## Build refusal into the threat model

Most AI security reviews focus on a model producing a wrong answer. A scanner might call malicious code safe, invent a benign explanation, or miss an obfuscated branch. GuardBreaker points to a different outcome: the model produces no usable answer, and the application fails around it.

That means the threat model must include every control outside the model. What prepares the input? Which material reaches the provider's safety filter? Can the model call tools? How does the parser recognise completion? What happens after a refusal? Who can see incomplete scans? Which action is blocked while the result remains uncertain?

Start with the trust boundary. Source code, package metadata, documentation, comments, issue descriptions, commit messages, generated logs, and sample data are all attacker-controlled when they arrive from an unknown repository or public contribution. Their human-readable appearance does not make them instructions the scanner should follow. Marking them as data in the prompt is sensible, but enforcement must continue after that prompt.

The output parser should require a positive completion signal. If the application expects structured data, validate the schema and an explicit status field rather than inferring safety from an empty findings array. Reject truncated output. Keep provider errors and content-policy blocks distinct from completed analysis. Do not let a natural-language apology satisfy the same parser as a security verdict.

The release policy then consumes the status. A high-risk artifact with an incomplete scan should stop before publication, signing, deployment, or installation on a privileged runner. A lower-risk artifact may proceed to an isolated test after independent checks, but the exception should remain visible. Risk tolerance changes the next action, not the historical fact that analysis failed.

Network and identity boundaries still matter because scanners increasingly act rather than only read. An analysis agent may unpack archives, resolve dependencies, run tools, query threat-intelligence services, or submit samples elsewhere. Give that environment a narrow filesystem, temporary credentials, and controlled destinations. Hostile evidence should not inherit the analyst's cloud session simply because the scanner wants more context.

Data handling needs equal care. Malware samples can contain customer information, internal paths, API keys, or stolen documents. Sending the entire file to an external model may violate policy even when the model would analyse it correctly. Decide which providers and regions are approved, what retention terms apply, and which classes of evidence must stay local. A refusal should not tempt an analyst to bypass those rules with a personal account.

Version the decision path. Record the prompt template, model identifier, filter configuration where exposed, parser version, and fallback policy alongside test results. Providers can change guardrails without changing your application code. A previously safe integration can therefore acquire a new refusal pattern between two deployments.

Finally, assign an owner to scanner incompletes. A metric nobody owns becomes scenery. The owner should know how many scans completed, how many refused, how many failed operationally, which artifact types were affected, and whether any release proceeded through a fallback. A sudden cluster of refusals deserves investigation even when every artifact later proves harmless.

This is the Secure Harness pattern in a small form. The goal is not to predict every sentence an attacker might plant. Put the uncertain model decision inside a system that records failure, limits effects, and keeps a separate route to a trustworthy answer.

## Test the failure path before an attacker does

Teams usually test whether the scanner catches malware. They should also test whether the pipeline behaves safely when the scanner cannot answer. That second test can use harmless fixtures and synthetic refusals. There is no need to circulate live malware or offensive content through production services.

Begin in a development environment with fake artifacts and no production credentials. Stub the model adapter so it can return each supported state: clean completion, finding, content-policy refusal, timeout, malformed structured output, rate limit, and provider outage. Then follow each state to the final release decision.

The test is successful only if the difference remains visible all the way through. A refusal that appears in an adapter log but becomes a green check in the build interface has failed the exercise. A malformed result that blocks one job but disappears from security reporting has also failed, because repeated manipulation could remain hidden.

Use a small decision table before writing more automation. It might say that a completed clean result contributes one signal but cannot override a critical static finding. A completed malicious result quarantines the artifact. A refusal marks the artifact unassessed, raises an event, and invokes independent checks. An operational error follows a bounded retry policy before the same unassessed state. The exact labels matter less than preserving their meaning.

Then test adversarial text with provider-approved, benign fixtures. The purpose is to see whether instructions embedded in comments, README files, package descriptions, logs, or filenames can alter the analysis contract. Avoid real requests for dangerous instructions. A fixture can simply tell the model to stop, return an invalid schema, or claim that later content is trusted. The scanner should identify the manipulation or at least fail visibly.

Do not build the defence around stripping comments. Comments sometimes carry analyst-relevant clues, configuration directives, encoded material, copied commands, or explanations of attacker intent. Removing them can erase evidence and still leaves strings, identifiers, documentation files, and metadata available for injection. A second analysis view with comments neutralised may be useful, but it should complement preservation of the original artifact.

Test aggregation separately. Remove one engine's score and confirm that confidence does not rise. Force two nominally different scanners to fail through a shared provider and see whether the dashboard exposes the common dependency. Change the model version in staging and compare refusal rates before production rollout.

Exercise the human path as well. Can an engineer assign the artifact to a malware analyst without emailing it around? Does the analyst receive the hash, origin, prior results, and reason for escalation? Can they work in a controlled environment? Can they record a decision that the release gate actually consumes?

Measure time, but do not turn speed into the only objective. A fallback that takes eight minutes and preserves the distinction between clean and incomplete is better than a one-second default allow. For routine internal work, teams can reduce delay by precomputing structural checks, maintaining warm isolated workers, and defining which low-impact actions may continue while review is pending.

Run this exercise whenever the model provider, safety policy, prompt template, parser, or release rule changes. Add every real refusal pattern to the regression corpus after removing sensitive content. The test suite then becomes a record of how the integration has failed in practice, not a collection of guesses made during initial design.

One metric is especially revealing: the number of artifacts released after an incomplete analysis, broken down by reason and approved fallback. The ideal value may not be zero for every organisation. It should never be unknown.

## What to change this week

Keep language models in analysis, but remove the unsafe shortcut between “the model did not answer” and “continue.” Most teams can inspect that path without buying another product.

Start at the adapter where model output becomes an application result. Follow one refusal through queues, databases, dashboards, policy engines, build checks, and release jobs. Look for empty arrays, default false values, broad exception handlers, missing scores, and retries that discard the original reason. Those are the places where uncertainty can be laundered into approval.

1. **Give incomplete analysis its own status.** Represent refusal, timeout, provider error, malformed output, and completed analysis separately. Preserve the reason and artifact hash. Never encode an incomplete scan as `clean`, `false`, an empty findings list, or a score of zero.

2. **Make the release rule consume that status.** Block high-impact release actions when required analysis is incomplete. For lower-impact paths, document a fallback that uses independent checks and keeps the exception visible. Do not let a missing score improve the aggregate result.

3. **Keep non-model detection in the path.** Continue format-aware static analysis, package-policy checks, endpoint telemetry, sandboxing, reputation signals, and human review according to the artifact's risk. Confirm that these controls do not all depend on the same model provider or preprocessing service.

4. **Alert on suspicious refusals.** Route refusals tied to artifact content to the security queue, especially when several files trigger the same policy category or embedded instruction pattern. Rate-limit noisy alerts, but retain counts and samples so a deliberate campaign cannot hide as routine API friction.

5. **Constrain the analysis environment.** If the scanner unpacks, executes, or fetches anything, isolate it from developer home directories and production identities. Restrict outbound destinations. Use temporary credentials. Keep sample submission inside approved data-handling rules.

6. **Add refusal cases to the regression suite.** Stub every API failure mode and use benign prompt-injection fixtures across comments, metadata, documentation, and logs. Verify the final dashboard and release decision, not only the model response. Repeat the suite after provider or policy changes.

7. **Ask vendors a precise question.** “What happens to my artifact when the model refuses or your output filter blocks the response?” Request the observable status, fallback behaviour, release effect, audit record, and evidence that incomplete scans cannot appear clean. A general claim about layered AI safety does not answer that operational question.

8. **Review recent incompletes.** Search the last 30 days of scanner logs for refusals, empty results, parse failures, and provider errors. Compare those events with artifacts that were released. Escalate content-linked clusters and investigate according to the environment each artifact could reach.

This sequence gives engineering, security, and platform teams a shared object to inspect. The model team owns the adapter and evaluations. Security owns the risk rule and investigation path. Platform engineering owns the isolation and release enforcement. Product teams can see why a job paused instead of receiving an unexplained red build.

A small organisation using a model manually can apply the same rule. If the chat refuses to analyse a suspicious file, do not conclude that the file contains nothing important. Stop moving it through ordinary workstations, use your established security tooling, and ask a qualified analyst or vendor for help. Do not paste the sample into a string of personal AI accounts until one agrees to answer.

The most valuable code change may be an enum and a release condition. The most valuable process change may be showing refusals to the same people who see malware findings. Neither is glamorous. Both make the attacker's planted sentence less useful.

## Safety controls must fail in the right direction

The UAC-0099 sample is memorable because the bait sounds extreme while the engineering error is mundane. A safety layer declined to engage with dangerous language. The surrounding application may then face an ordinary exception-handling decision. That is where a protective refusal can become an attacker's off switch.

The evidence available on 1 September 2026 does not justify claims that AI malware scanners are broadly defeated, that one phrase bypasses every model, or that ESET documented a named product failure in the field. It does justify a direct review of how scanners represent and route incomplete analysis. JFrog's earlier tests show that refusal behaviour varies by model interface and policy, which makes assumptions about one successful test especially fragile.

Models still belong in defensive analysis. They can read code at useful speed and explain patterns that would cost a human more time. Their output becomes dependable when a completed verdict is distinguishable from a blocked one, when independent checks survive, and when the system can stop a release without asking the model to be infallible.

Attackers are writing for the AI reader now. Defenders should assume every file may contain two programs: the code meant for the computer and the language meant for the scanner. One can be inert at runtime and active in the decision path.

Treat both as hostile input. Keep refusal visible. Make uncertainty reduce authority rather than increase it. Then a model can look away without taking the rest of the security system with it.

For more calm, practical security explanations, join the newsletter. It is one email per month.

## Sources

- [ESET Research: GuardBreaker finding on UAC-0099](https://x.com/ESETresearch/status/2092885122584285666), accessed 2026-09-01
- [Help Net Security: Russian hackers plant nuclear weapon prompt in malware to trip AI safety guardrails](https://www.helpnetsecurity.com/2026/08/31/russian-hackers-ai-safety-filters-manipulation/), accessed 2026-09-01
- [The Hacker News: Russia-Aligned UAC-0099 Plants Nuclear Weapon Prompt in Malware to Disrupt AI Analysis](https://thehackernews.com/2026/09/russia-aligned-uac-0099-plants-nuclear.html), accessed 2026-09-01
- [CERT-UA: UAC-0099, LUNCHPOKE, BURNYBEAR, updated MATCHBOIL.V2, and use of Notepad++ 8.8.3](https://cert.gov.ua/article/6318634), accessed 2026-09-01
- [JFrog Security Research: The malware that wants your AI scanner to look away](https://research.jfrog.com/post/prompt-injection-vs-scanners/), accessed 2026-09-01

---

## About the author

Kubilay Tunca — Senior Full Stack Developer and Author. Founded Cyber Security in Plain English to translate complex security concepts into clear, practical advice, and writes the accompanying books on security, privacy, secure development, and AI systems.

## Books by this author

- **The Digital Fortress** — Your Everyday Guide to a Safer Digital Life. A warm, plain-English guide for people with real lives and finite patience. Learn the handful of habits that genuinely protect your money, accounts, and family, and get honest permission to ignore the rest. [Amazon](https://buy.cyber-security-in-plain-english.com/digital-fortress) · [Details](https://cyber-security-in-plain-english.com/books/the-digital-fortress)
- **The Anonymity Playbook** — Digital Survival for Whistleblowers, Journalists, Activists, and Everyone Else. A practitioner’s field manual for journalists protecting sources, whistleblowers, and activists. It explains how the surveillance actually works, what each technique costs you, and exactly where it fails. [Amazon](https://buy.cyber-security-in-plain-english.com/anonymity-playbook) · [Details](https://cyber-security-in-plain-english.com/books/the-anonymity-playbook)
- **Secure Software Development** — Practical patterns for building secure software. A hands-on security guide for developers and IT professionals who ship real software. Build, deploy, and maintain secure systems without slowing down or drowning in theory. [Amazon](https://buy.cyber-security-in-plain-english.com/secure-software-development) · [Details](https://cyber-security-in-plain-english.com/books/secure-software-development)
- **The Secure Harness** — Shipping Production Code with AI Coding Agents. A calm, practical guide to letting agents do useful work inside boundaries you set, enforce, and audit. Ships with 15 copy-pasteable artifacts: hook scripts, permission configs, release gates, and MCP templates. [Amazon](https://buy.cyber-security-in-plain-english.com/secure-harness) · [Details](https://cyber-security-in-plain-english.com/books/the-secure-harness)
- **The AI Native Engineer** — Build, Evaluate, and Ship AI Systems That Work in Production. Sixteen hands-on chapters, one real product. Grow it from a single model call into a retrieved, tool-using, observable, production-grade system, with evaluation treated as a habit from the first feature. [Amazon](https://buy.cyber-security-in-plain-english.com/ai-native-engineer) · [Details](https://cyber-security-in-plain-english.com/books/the-ai-native-engineer)

Full catalogue with contents and intended audience: https://cyber-security-in-plain-english.com/books

_As an Amazon Associate I earn from qualifying purchases. Buying through these links costs you nothing extra and helps pay for the blog._
