Securing the agentic AI software supply chain
← Research
Threat report Jul 29, 2026

Loaded but not fired: tchain-api ships encrypted key material and the machinery to read it

tchain-api (published by the account hallisaacpna555) poses as a Turborepo and Next.js monorepo while carrying two CryptoJS-encrypted blobs, rsa.db and des.db, plus a module that reads both and re-exports them as rsaKey and desKey. The module neither decrypts nor runs that material, and no network activity ships in this version. The carrier structure matches the encrypted-payload tradecraft previously documented in the thedata package, at moderate confidence.

tchain-api (v1.2.5) was published to npm by the account hallisaacpna555. It presents itself as a Turborepo and Next.js monorepo, with apps/docs, apps/web, and packages/ui filled out with the scaffolded boilerplate that create-next-app and create-turbo generate. Under that cover it ships two files, apps/docs/app/rsa.db and apps/docs/app/des.db, whose contents are CryptoJS-encrypted blobs. A single module reads both files and re-exports their bytes. The package neither decrypts nor runs the material, and no exfiltration is present in this version.

The package is a staging precursor. It carries encrypted material and the machinery that surfaces it to any consumer, which is the step that comes before a later version or a downstream importer decrypts and runs that material. The carrier structure here matches the encrypted-payload tradecraft this research program documented earlier in the thedata package, which read rsa.db and des.db the same way. That gives moderate confidence that tchain-api belongs to the same operation or reuses its toolkit.

The artifact

tchain-api is a single package under the account hallisaacpna555, its only publication. It was released in four versions within roughly 2.5 hours on the same day, a release velocity consistent with active iteration on a work in progress.

The repository is dressed to pass a quick read. The root package.json declares a Turborepo workspace over apps/* and packages/* with the standard turbo build, turbo dev, and turbo lint scripts. The apps/docs and apps/web trees hold the default Next.js README and the stock next.svg and vercel.svg assets, plus an eslint config lifted from the Turborepo template. None of that scaffolding does anything. It exists so the package looks like an ordinary monorepo when a reviewer skims the file list.

The README points elsewhere. It embeds a “Chain Hero Image” pulled from raw.githubusercontent[.]com/b-bot/chain/main/chain.jpg and links every badge to an npm package named chain. The published artifact is tchain-api while the README markets a package called chain, so the visible advertising names something other than what a reader installs. That mismatch is the same lure pattern seen across this class of package, where the visible marketing points at a plausible-sounding project the reader is expected to trust.

One more discrepancy sits inside the workspace. The apps/docs/package.json is named thetachain-docs, sets "main": "./app/theta.ts", and its files array lists app/theta.ts and app/data.db. The package does not ship app/data.db. It ships rsa.db and des.db instead. The manifest describes one payload file while the tree carries two under different names.

What it does

The two .db files hold ciphertext. rsa.db begins with the base64 text U2FsdGVkX18q77TIYtph... and des.db begins with U2FsdGVkX18IXFVhY9Ht.... Decoding the shared eight-character prefix U2FsdGVkX18 from base64 yields the ASCII bytes Salted__, the header CryptoJS and OpenSSL write in front of an encrypted blob. The .db extension and the key-sounding variable names are cover for encrypted payload storage.

The read-and-export lives in apps/docs/app/theta.ts. It is eight lines:

import { readFileSync } from "node:fs";
import { fileURLToPath } from "node:url";

const rsaPath = fileURLToPath(new URL("./rsa.db", import.meta.url));
const desPath = fileURLToPath(new URL("./des.db", import.meta.url));

export const rsaKey = readFileSync(rsaPath, "utf8");
export const desKey = readFileSync(desPath, "utf8");

The module resolves each .db file relative to itself, reads it as UTF-8 text, and exports the raw contents as rsaKey and desKey. The root index.js is a single line that re-exports the module:

export { theta } from "./apps/docs/app/theta.ts";

That is the whole mechanism. There is no CryptoJS.decrypt, no child_process, no spawn, no fetch, no writeFileSync to a temp path, and no outbound address anywhere in the package. The encrypted blobs are read and handed to whatever imports the module. What decrypts them and what runs the result is not shipped here.

One literal in the tree can be mistaken for an indicator. The string 3.5.7.9 appears inside apps/docs/public/next.svg, where it is SVG path-coordinate data in the stock Next.js logo. No command-and-control endpoint was recovered from this version, and none exists in it. The package carries the capability in encrypted form without the code to activate it.

rsa.db + des.db base64 Salted__, CryptoJS-encrypted blobs theta.ts readFileSync(rsa.db), readFileSync(des.db) export rsaKey, desKey index.js re-exports theta Awaiting a later decrypt-and-run stage Neither decrypts nor runs, and makes no network call Aephix
The staging chain: two encrypted blobs read and re-exported, with the decrypt-and-run stage absent from this version.

The tradecraft matches an operation already on record

The rsaKey and desKey pair, read out of .db files that hold base64 Salted__ blobs, is a distinctive carrier. This research program documented the same carrier in the thedata package, part of the encrypted-dropper operation whose lure imported a DES-encrypted blob from a sibling package, then decrypted and spawned it as a detached process. In that case thedata exposed rsaKey and desKey from encrypted .db files exactly as tchain-api does here.

tchain-api shares that encrypted-payload-carrier tradecraft. The supporting evidence is the identical file layout and export surface, the same Salted__ blob encoding, the shared monorepo dressing used as cover, and a compressed release cadence on a single day. That is enough to place the two artifacts together at moderate confidence. Whether tchain-api is the same operation or a separate actor reusing its toolkit stays an open question, and this analysis does not close it.

Catching the staging step is the point

A package that only reads and re-exports two files does nothing overtly hostile at rest. It installs cleanly and passes a lint, and importing it raises no error. A scanner looking for decrypt calls or spawned processes finds neither, and no outbound connection is present because none is here yet. The malicious capability is staged one delivery away, in the ciphertext of rsa.db and des.db and in whatever later version or consumer supplies the key and the runner.

Value comes from recognizing the precursor before the payload arrives. The carrier structure, the Salted__ blobs behind key-named files, the README pointing at a different package, and the four-versions-in-hours cadence are all observable now. Treating tchain-api as benign because this version does not execute anything is the error the staging design is built to produce.

What a defender can do

Search your lockfiles for tchain-api. If it resolved, treat the encrypted .db files as an untrusted payload and preserve them for analysis rather than importing the module. Any consumer that imports theta and passes rsaKey or desKey into a decrypt-and-execute path is the completion of the chain, so audit for code that does so.

Be skeptical of packages whose README advertises a different package name than the one on the registry, and of .db or data files whose first bytes decode to Salted__. Static review of this package tells you it carries encrypted material and surfaces it, which is a reason to withhold trust even though the package does not run the material itself. That gap, between a component that is clearly staging something and a component you can prove is hostile before you connect it, is where package-by-package review runs out.

Indicators of compromise

TypeIndicatorContext
npm packagetchain-api (v1.2.5, four versions in ~2.5 hours)Staging precursor posing as a Turborepo monorepo
npm accounthallisaacpna555Sole publisher of tchain-api
Fileapps/docs/app/rsa.dbbase64 Salted__ header, CryptoJS-encrypted blob holding ciphertext
Fileapps/docs/app/des.dbbase64 Salted__ header, CryptoJS-encrypted blob holding ciphertext
Sourceapps/docs/app/theta.tsReads both .db files with readFileSync, exports rsaKey and desKey
Sourceindex.jsRe-exports theta
Manifest mismatchthetachain-docs files lists app/data.dbTree ships rsa.db and des.db instead
README luregithub[.]com/b-bot/chain hero image, links to npm package chainMarketing points at a different package name than tchain-api
Cover scaffoldingapps/web, packages/ui, stock Next.js assetsBoilerplate filler, no functional role
Not an indicator3.5.7.9 in apps/docs/public/next.svgSVG path-coordinate data in the stock Next.js logo
AbsentCommand-and-control endpointNone present or recovered in this version

Where Aephix fits

This is where Aephix earns its place. Aephix is threat intelligence for the AI agent supply chain. It is not a patch or a sandbox. Before you install a package or connect to a server, Aephix Vantage gives you a free, cross-ecosystem view of what is already known to be malicious, so a carrier package that stages encrypted material is something you recognize before you import it. When you are looking at a package, model, skill, MCP server, extension, or container like tchain-api, Aephix Sleuth links it to the wider operation behind it, with a confidence level and supporting evidence, so you can act against the whole operation and its future republishes rather than the single staged artifact.