
Research
Shai-Hulud Descends to Hades: Miasma Worm Campaign Spreads with New PyPI Wave
Socket found 37 malicious PyPI wheels that abuse Python startup hooks to launch a Bun-powered credential stealer tied to Mini Shai-Hulud/Miasma.
@replit/crosis
Advanced tools
yarn add @replit/crosis @replit/protocol
Crosis relies on the @replit/protocol package as a peer dependency. https://github.com/replit/protocol
You should probably familiarize yourself with the protocol before trying to use it. Crosis is just a client that helps you connect and communicate with the container using the protocol.
Read about the protocol here https://crosis-doc.util.repl.co/
The central concept is a "channel" that you can send commands to and receive commands from. Communicating with channels requires a network connection. The goal of this client is to provide an API to manage the connection (including disconnects and reconnects), opening channels, and a way to send a receive messages/commands on channels. How you handle this is up to you and depends on the desired UX. In some cases you'll want to disable UI to prevent any new messages from being sent when offline and then re-enable once connected again. In other cases you might want to give the user the illusion that they are connected and queue messages locally while disconnected and send them once reconnected.
Here is an example usage, for more details on usage please refer to the API docs at https://crosisdoc.util.repl.co/
import { Client } from '@replit/crosis';
const client = new Client<{ user: { name: string }; repl: { id: string } }>();
const repl = { id: 'someuuid' };
async function fetchConnectionMetadata(
signal: AbortSignal,
): Promise<FetchConnectionMetadataResult> {
let res: Response;
try {
res = await fetch(CONNECTION_METADATA_URL + repl.id, { signal });
} catch (error) {
if (error.name === 'AbortError') {
return {
error: FetchConnectionMetadataError.Aborted,
};
}
throw error;
}
if (!res.ok) {
if (res.status > 500) {
// Network or server error, try again
return {
error: FetchConnectionMetadataError.Retriable,
};
}
const errorText = await res.text();
throw new Error(errorText || res.statusText);
}
const connectionMetadata = await res.json();
return {
token: connectionMetadata.token,
gurl: connectionMetadata.gurl,
conmanURL: connectionMetadata.conmanURL,
error: null,
};
}
const user = { name: 'tim' };
const context = { user, repl };
client.open({ context, fetchConnectionMetadata }, function onOpen({ channel, context }) {
if (!channel) {
// Closed before ever connecting. Due to `client.close` being called
// or an unrecoverable, that can be handled by setting `client.setUnrecoverableError`
return;
}
// The client is now connected (or reconnected in the event that it encountered an unexpected disconnect)
// `channel` here is channel0 (more info at https://crosis-doc.util.repl.co/protov2)
// - send commands using `channel.send`
// - listen for commands using `channel.onCommand(cmd => ...)`
return function cleanup({ willReconnect }) {
// The client was closed and might reconnect if it was closed unexpectedly
};
});
// See docs for exec service here https://crosis-doc.util.repl.co/services#exec
const closeChannel = client.openChannel({ service: 'exec' }, function open({ channel, context }) {
if (!channel) {
// Closed before ever connecting. Due to `client.close` being called, `closeChannel` being called
// or an unrecoverable, that can be handled by setting `client.setUnrecoverableErr
return;
}
channel.onCommand((cmd) => {
if (cmd.output) {
terminal.write(cmd.output);
}
});
const intervalId = setInterval(() => {
channel.send({
exec: { args: ['echo', 'hello', context.user.name] },
blocking: true,
});
}, 100);
return function cleanup({ willReconnect }) {
clearInterval(intervalId);
};
});
To run tests run
USER_KEY_ID=XXXX USER_PRIVATE_KEY=XXXX yarn test
To interact with a connected client in the browser run
USER_KEY_ID=XXXX USER_PRIVATE_KEY=XXXX yarn debug
You can then access the client from the console an send messages like:
window.client.send({ exec: { args: ['kill', '1'] } });
To release, just run USER_KEY_ID=XXXX USER_PRIVATE_KEY=XXXX yarn version, it will prompt you for a version, then it will push to github and release to npm.
To update documentation, go to https://crosisdoc.util.repl.co/__repl and run . ./updatedocs.sh
FAQs
Goval connection and channel manager
The npm package @replit/crosis receives a total of 24,580 weekly downloads. As such, @replit/crosis popularity was classified as popular.
We found that @replit/crosis demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 23 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Research
Socket found 37 malicious PyPI wheels that abuse Python startup hooks to launch a Bun-powered credential stealer tied to Mini Shai-Hulud/Miasma.

Security News
RubyGems and Bundler 4.0.13 introduced an opt-in cooldown feature that delays newly published gems during dependency resolution.

Security News
pnpm 11.5 now recognizes npm staged publish approvals in release metadata, preventing those releases from being mistaken for lower-trust package publishes.