DeviceDoor npm Package Shipping a Microsoft 365 Device-Code Phishing Framework

DeviceDoor: a public npm package shipping a Microsoft 365 device-code phishing and bulk-mail framework

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.

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. 

sca-tools-software-composition-analysis-tools
Prioritize, remediate, and secure your software risks
7-day free trial
No credit card required

Secure your Software Development and Delivery

with Xygeni Product Suite