TL;DR
nolimit-agent is an npm package whose published versions — 1.0.299 through 1.0.307, released over four days from 2026-06-26 to 2026-06-29 — each carry a complete phishing and bulk-mail framework inside a hidden, fully obfuscated directory. In every version the main entry resolves to .ad/x0.js, one of ~86 files in a dotfile-named folder holding roughly 4,200 javascript-obfuscator string-array blobs; the install hook and entry layout are identical across the line.
Behind the obfuscation sits a Microsoft 365 OAuth device-code flow (login[.]microsoftonline[.]com/common/oauth2/v2.0/devicecode) that, once a code is approved, reads the victim's Outlook inbox and sent items through the Microsoft Graph API; a bulk SMTP and SMS sending engine driven by operator-supplied recipient lists; brand-impersonation message templates; open-redirect link construction; and reconnaissance over DNS-over-HTTPS, WHOIS, and GitHub code search. Runtime traffic beacons to operator infrastructure at api[.]nolimitent[.]xyz:4100.
Affected: anyone who installs any version of the package, and any Microsoft 365 mailbox whose owner approves a device code presented through it. The most recent version, 1.0.307, is the current latest tag and carries the same device-code mailbox capability — the malicious code is not confined to one back-version.
Severity: critical. Affected ecosystem: npm. The one indicator to search for first: the host api[.]nolimitent[.]xyz.
The attack: how it works
A benign shell over a hidden payload
The package presents an ordinary surface. package.json declares a postinstall hook –
text
postinstall: node scripts/postinstall.js
— and on inspection scripts/postinstall.js is harmless: it installs a Windows command shim and exits. The hook is not where the behavior lives. The main and bin fields both point into .ad/, a directory whose leading dot keeps it out of casual ls output, and whose contents are uniformly machine-obfuscated. The static scanner counted ~4,293 encoded-payload spans across the .ad/ module set; javascript-obfuscator is a declared development dependency, which matches the string-array-rotation shape of the bundled files.
The split is the first signal worth naming: the install hook a reviewer would scrutinize is clean, while the operational code sits one directory away, hidden and obfuscated, reached only when the package’s exported entry point runs.
Microsoft 365 device-code mailbox access
The module .ad/x12.js carries the framework’s most consequential capability. It drives the Microsoft 365 OAuth 2.0 device authorization grant:
text
POST login[.]microsoftonline[.]com/common/oauth2/v2.0/devicecode
The device-code grant is a legitimate Microsoft flow designed for input-constrained devices: a service requests a code, the user types that code into microsoft.com/devicelogin` on a second device and approves, and the requesting service receives tokens. When the requesting service belongs to someone other than the mailbox owner, approval hands that third party a token. Once a token is obtained, .ad/x12.js` reads the mailbox directly through Microsoft Graph:
text
GET graph[.]microsoft[.]com/v1.0/me/mailFolders/inbox/messages?$top=250&$select=from
GET graph[.]microsoft[.]com/v1.0/me/mailFolders/sentitems/messages?$top=250&$select=toRecipients
The $select projections pull sender addresses from the inbox and recipient addresses from sent items — the raw material for mapping a victim’s correspondents. This is adversary-in-the-middle (AiTM) access by consent rather than by password capture: there is no credential to phish in the classic sense, only a code to get approved.
A bulk mail and SMS engine with impersonation templates
Around the mailbox access sits a mailer. The package ships operator-editable data files — sender lists (senders.txt, smtps.txt) and a template file (functions.txt) — whose placeholder addresses read as a casting sheet for impersonation: security@apple.com, login-verification, OAuth-service, billing, and account-notification senders against a yourdomain.com stand-in the operator replaces. The SMS side carries a phonebook and gateway configuration. The mailer iterates operator-supplied recipient lists and sends through configured SMTP relays.
To make links land, .ad/xu.js and .ad/xq.js build URLs that exploit URL parsing ambiguity and click tracking. The spoof patterns embed a trusted-looking authority before an @ so the visible prefix differs from the real host:
text
https://trusted[.]com@ https://trusted[.]com%40 https://trusted[.]com:80@
https://redirect[.]example[.]com/ https://track[.]example[.]com/click?
The framework also grabs favicons from major consumer and enterprise mail providers — a routine technique for rendering a convincing provider-branded prompt or landing page.
Target and infrastructure reconnaissance
Several modules gather context before sending. .ad/x0.js resolves names over DNS-over-HTTPS (dns[.]google/resolve), .ad/xa.js queries WHOIS (api[.]whois[.]vu), and .ad/x9.js runs GitHub code search (api[.]github[.]com/search/code?q=) — a pattern consistent with discovering exposed mail-server configuration and SMTP credentials to feed the relay list. .ad/xs.js queries the Wayback Machine’s CDX index.
Command and control
Across the obfuscated set, .ad/x4.js references the operator endpoint:
text
http://api[.]nolimitent[.]xyz:4100
The host shares its nolimitent brand with the publisher’s own naming, and the :4100 port is the framework’s call-home channel. This is the single most durable indicator for defenders: a package, a developer workstation, or a build agent reaching api[.]nolimitent[.]xyz has run this code.
Indicators of compromise
The indicators below are the ones a defender can act on — grep a lockfile, block a host, or search proxy and DNS logs. Microsoft endpoints appear because the framework abuses them; they are not themselves malicious and should not be blocked.
| Indicator | Type | Where | Defender action |
|---|---|---|---|
nolimit-agent (all versions 1.0.299–1.0.307) |
Package | npm | Grep lockfiles / install logs |
api[.]nolimitent[.]xyz (:4100) |
C2 host | .ad/x4.js |
Block; search DNS + proxy logs |
.ad/ hidden dir as main/bin target |
Structure | package.json |
Static signal in registry review |
trusted[.]com@ / %40 / :80@ link forms |
URL spoof | .ad/xu.js, .ad/xq.js |
Mail/proxy URL inspection |
Device-code grant + Graph inbox/sentitems read |
Behavior | .ad/x12.js |
M365 sign-in + Graph audit review |
File hashes captured at triage:
- package/.ad/x0.js — sha256 e4153bb614ee03ec456e6b5b41926385db6aae0e4f3e771d18e581571ad7ca2a
- package/package.json — sha256 8618064f1f6146b4a8f0459aff9154dca1847e3936aa44f4d4cd37e127075644
A Microsoft 365 tenant signal worth hunting independent of this package: successful device-code sign-ins followed promptly by Graph reads of mailFolders/inbox and mailFolders/sentitems, especially from a session the user does not recognize.
Attribution & observed behavior
What is observable stays separate from who is behind it.
Observable facts: the package is published under the handle nolimit-agent with an unverified Gmail address and no linked source repository; its package.json describes it as an “advanced email sender” and tags it with the red-team keyword; the runtime code is concentrated in a hidden, obfuscated .ad/ directory whose toolchain (javascript-obfuscator) is a declared dependency; and the call-home host api[.]nolimitent[.]xyz reuses the nolimitent brand. This is a single package with one operator-controlled infrastructure landmark — not a multi-package cluster, and no overlap with a previously named campaign was identified.
The red-team keyword does not change the classification. Legitimate offensive-security tooling that ships dual-use capability does so transparently: readable source, operator-supplied targets, and no hidden call-home. This package inverts each of those properties — its operational code is obfuscated and hidden, and it beacons to fixed operator infrastructure rather than a target the user supplies. The behavior, not the label, governs the verdict, which is malicious.
Intent is not asserted here. The post describes what the code does — request a device code, read a mailbox over Graph, send bulk mail through configured relays, beacon to a fixed host — and leaves motive unstated.
Impact, trends & defender guidance
Two installation-time effects matter. First, any developer or CI agent that installs nolimit-agent brings the framework onto that host and establishes the call-home to api[.]nolimitent[.]xyz. Second, the device-code capability extends reach beyond the installing host: a Microsoft 365 mailbox whose owner is induced to approve a presented code is read directly through Graph, with no password ever crossing the wire.
The broader trend is the one to internalize. Device-code (AiTM) phishing has moved from standalone phishing infrastructure into a package on a public registry — distribution by npm install rather than by emailed link. Packaging the kit this way trades the phishing operator’s hosting and link-delivery problem for a registry’s reach, and hides the operational code behind a clean install hook and a dotfile-named obfuscated directory that defeats a quick manual skim.
For defenders:
- Registry and dependency review. Treat a package whose main/bin resolves into a hidden (dot-prefixed) directory of uniformly obfuscated first-party code as high-risk on structure alone, independent of whether the install hook looks clean. Minification is not obfuscation — gate on the string-array decoder signature, not on line length.
- Microsoft 365 hardening. Restrict the device-code authorization flow with Conditional Access where it is not operationally required; device-code grants are a known AiTM vector and are rarely needed by interactive users. Audit for device-code sign-ins followed by immediate Graph mailbox enumeration.
- Network detection. Block and alert on api[.]nolimitent[.]xyz. Hunt outbound DNS and proxy logs for it across developer and build infrastructure.
- Mail-path detection. The user@host URL-spoof forms (trusted[.]com@…) are detectable at the mail gateway and proxy; flag links whose authority component precedes an @.
The package was live on npm at the time of analysis. Because the hidden framework spans the entire published version line and the current latest tag (1.0.307) carries the device-code capability, registry takedown should cover every version, not only a single back-version.




