Research
Security News
Quasar RAT Disguised as an npm Package for Detecting Vulnerabilities in Ethereum Smart Contracts
Socket researchers uncover a malicious npm package posing as a tool for detecting vulnerabilities in Etherium smart contracts.
@microsoft/teamsfx
Advanced tools
Microsoft Teams Framework for Node.js and browser.
TeamsFx aims to reduce the developer tasks of leveraging Teams SSO and access to cloud resources down to single-line statements with "zero configuration".
Use the library to:
Source code | Package (NPM) | API reference documentation | Samples
Important: Please be advised that access tokens are stored in sessionStorage for you by default. This can make it possible for malicious code in your app (or code pasted into a console on your page) to access APIs at the same privilege level as your client application. Please ensure you only request the minimum necessary scopes from your client application, and perform any sensitive operations from server side code that your client has to authenticate with.
TeamsFx SDK is pre-configured in scaffolded project using Teams Toolkit extension for Visual Studio and vscode, or the teamsfx
cli from the teamsfx-cli
npm package.
Please check the README to see how to create a Teams App project.
teamsfx
CLI tool.botbuilder
related packages as dependencies, ensure they are of the same version and the version >= 4.18.0
. (Issue - all of the BOTBUILDER packages should be the same version)@microsoft/teamsfx
packageInstall the TeamsFx SDK for TypeScript/JavaScript with npm
:
npm install @microsoft/teamsfx
TeamsFx SDK is built to be used in browser and NodeJS environment. Common scenarios include:
createMicrosoftGraphClientWithCredential
or createMicrosoftGraphClient
[!NOTE]
createMicrosoftGraphClient
andcreateMicrosoftGraphClientWithCredential
function has been deprecated. It is recommended that you to useClient
andTokenCredentialAuthenticationProvider
from@microsoft/microsoft-graph-client
instead, for better coding experience.
To create a graph client object to access the Microsoft Graph API, you will need the credential to do authentication. The SDK provides APIs to configure for developers. Please choose the proper identity type and follow below steps:
Use the snippet below (Recommended):
import { TeamsUserCredentialAuthConfig, TeamsUserCredential } from "@microsoft/teamsfx";
import { Client } from "@microsoft/microsoft-graph-client";
import { TokenCredentialAuthenticationProvider } from "@microsoft/microsoft-graph-client/authProviders/azureTokenCredentials";
const authConfig: TeamsUserCredentialAuthConfig = {
clientId: process.env.REACT_APP_CLIENT_ID,
initiateLoginEndpoint: process.env.REACT_APP_START_LOGIN_PAGE_URL,
};
const teamsUserCredential = new TeamsUserCredential(authConfig);
const authProvider = new TokenCredentialAuthenticationProvider(credential, {
scopes: ["User.Read"],
});
const graphClient = Client.initWithMiddleware({ authProvider: authProvider });
const profile = await graphClient.api("/me").get();
or use createMicrosoftGraphClientWithCredential
as below (Deprecated):
const authConfig: TeamsUserCredentialAuthConfig = {
clientId: process.env.REACT_APP_CLIENT_ID,
initiateLoginEndpoint: process.env.REACT_APP_START_LOGIN_PAGE_URL,
};
const teamsUserCredential = new TeamsUserCredential(authConfig);
const graphClient = createMicrosoftGraphClientWithCredential(teamsUserCredential, ["User.Read"]);
const profile = await graphClient.api("/me").get();
or use createMicrosoftGraphClient
as below (Deprecated):
// Equivalent to:
// const teamsfx = new TeamsFx(IdentityType.User, {
// initiateLoginEndpoint: process.env.REACT_APP_START_LOGIN_PAGE_URL,
// clientId: process.env.REACT_APP_CLIENT_ID,
// });
const teamsfx = new TeamsFx();
const graphClient = createMicrosoftGraphClient(teamsfx, ["User.Read"]); // Initializes MS Graph SDK using our MsGraphAuthProvider
const profile = await graphClient.api("/me").get(); // Get the profile of current user
It doesn't require the interaction with Teams user. You can call Microsoft Graph as application identity.
Use the snippet below (Recommended):
import { AppCredentialAuthConfig, AppCredential } from "@microsoft/teamsfx";
import { Client } from "@microsoft/microsoft-graph-client";
import { TokenCredentialAuthenticationProvider } from "@microsoft/microsoft-graph-client/authProviders/azureTokenCredentials";
const appAuthConfig: AppCredentialAuthConfig = {
authorityHost: process.env.M365_AUTHORITY_HOST,
clientId: process.env.M365_CLIENT_ID,
tenantId: process.env.M365_TENANT_ID,
clientSecret: process.env.M365_CLIENT_SECRET,
};
const appCredential = new AppCredential(appAuthConfig);
const authProvider = new TokenCredentialAuthenticationProvider(appCredential, {
scopes: ["https://graph.microsoft.com/.default"],
});
const graphClient = Client.initWithMiddleware({ authProvider: authProvider });
const profile = await graphClient.api("/users/{object_id_of_another_people}").get();
or use createMicrosoftGraphClientWithCredential
as below (Deprecated):
const appAuthConfig: AppCredentialAuthConfig = {
authorityHost: process.env.M365_AUTHORITY_HOST,
clientId: process.env.M365_CLIENT_ID,
tenantId: process.env.M365_TENANT_ID,
clientSecret: process.env.M365_CLIENT_SECRET,
};
const appCredential = new AppCredential(appAuthConfig);
const graphClient = createMicrosoftGraphClientWithCredential(appCredential);
const profile = await graphClient.api("/users/{object_id_of_another_people}").get();
or use createMicrosoftGraphClient
as below (Deprecated):
// Equivalent to:
// const teamsfx = new TeamsFx(IdentityType.App, {
// initiateLoginEndpoint: process.env.REACT_APP_START_LOGIN_PAGE_URL,
// clientId: process.env.REACT_APP_CLIENT_ID,
// });
const teamsfx = new TeamsFx(IdentityType.App);
const graphClient = createMicrosoftGraphClient(teamsfx);
const profile = await graphClient.api("/users/{object_id_of_another_people}").get(); // Get the profile of certain user
[!NOTE]
TeamsFx
class has been deprecated. It is recommended that you to use different credentials (TeamsUserCredential
,AppCredential
,OnBehalfOfUserCredential
) instead, for better coding experience.
TeamsFx
class instance reads all TeamsFx settings from environment variables by default. You can also set customized configuration values to override the default values. Please check Override configuration for details.
When creating a TeamsFx instance, you also need to specify the identity type. There are 2 identity types:
Using new TeamsFx(IdentityType.User)
means the application will be authenticated as current Teams user. This one is the default choice. You need to call TeamsFx:setSsoToken()
when you use user identity in NodeJS environment(without browser).
You can use TeamsFx:getUserInfo()
to get user's basic information.
TeamsFx:login()
is used to let user perform consent process if you want to use SSO to get access token for certain OAuth scopes.
Using new TeamsFx(IdentityType.App)
means the application will be authenticated as an application. The permission usually need administrator's approval.
TeamsFx:getCredential()
provides credential instances automatically corresponding to identity type:
Developers should choose identity type when initializing TeamsFx. SDK provides 2 types: User and App. After developer has specified the identity type when initializing TeamsFx, SDK uses different kinds of credential class to represent the identity and get access token by corresponding auth flow.
There are 3 credential classes that are used to help simplifying authentication. They are located under credential folder.
Credential classes implements TokenCredential
interface that is broadly used in Azure library APIs. They are designed to provide access token for specific scopes. Other APIs that relies on credential call TeamsFx:getCredential()
to get an instance of TokenCredential
.
Here's the corresponding scenarios that each credential class targets.
TeamsUserCredential
represents Teams current user's identity. Using this credential will request user consent at the first time. It leverages the Teams SSO and On-Behalf-Of flow to do token exchange. SDK uses this credential when developer choose "User" identity in browser environment.
The following code is an an example to create TeamsUserCredential:
const authConfig: TeamsUserCredentialAuthConfig = {
clientId: process.env.REACT_APP_CLIENT_ID,
initiateLoginEndpoint: process.env.REACT_APP_START_LOGIN_PAGE_URL,
};
const credential = new TeamsUserCredential(authConfig);
Required configurations are initiateLoginEndpoint and clientId which can be found inside type TeamsUserCredentialAuthConfig.
OnBehalfOfUserCredential
uses On-Behalf-Of flow and need Teams ssoToken. It's designed to be used in Azure Function or Bot scenarios. SDK uses this credential when developer choose "User" identity in NodeJS environment.
The following code is an example to create OnBehalfOfUserCredential:
const oboAuthConfig: OnBehalfOfCredentialAuthConfig = {
authorityHost: process.env.M365_AUTHORITY_HOST,
clientId: process.env.M365_CLIENT_ID,
tenantId: process.env.M365_TENANT_ID,
clientSecret: process.env.M365_CLIENT_SECRET,
};
const oboCredential = new OnBehalfOfUserCredential(ssoToken, oboAuthConfig);
Required configurations are authorityHost, tenantId, clientId, clientSecret, or certificateContent which can be found inside type OnBehalfOfCredentialAuthConfig.
AppCredential
represents the application identity. It is usually used when user is not involved like time-triggered automation job. SDK uses this credential when developer choose "App" identity in NodeJS environment.
The following code is an example to create AppCredential
:
const appAuthConfig: AppCredentialAuthConfig = {
authorityHost: process.env.M365_AUTHORITY_HOST,
clientId: process.env.M365_CLIENT_ID,
tenantId: process.env.M365_TENANT_ID,
clientSecret: process.env.M365_CLIENT_SECRET,
};
const appCredential = new AppCredential(appAuthConfig);
Required configurations are authorityHost, tenantId, clientId, clientSecret, or certificateContent which can be found inside type AppCredentialAuthConfig.
Bot related classes are stored under bot folder.
TeamsBotSsoPrompt
has a good integration with Bot framework. It simplifies the authentication process when you develops bot application and want to leverage the Bot SSO.
The following code is an example to create TeamsBotSsoPrompt
:
const TeamsBotSsoPromptId = "TEAMS_BOT_SSO_PROMPT";
const settings: TeamsBotSsoPromptSettings = {
scopes: ["User.Read"],
timeout: 900000,
endOnInvalidMessage: true,
};
const authConfig: OnBehalfOfCredentialAuthConfig = {
authorityHost: process.env.M365_AUTHORITY_HOST,
clientId: process.env.M365_CLIENT_ID,
tenantId: process.env.M365_TENANT_ID,
clientSecret: process.env.M365_CLIENT_SECRET,
};
const loginUrl = process.env.INITIATE_LOGIN_ENDPOINT;
const ssoPrompt = new TeamsBotSsoPrompt(authConfig, loginUrl, TeamsBotSsoPromptId, settings);
TeamsFx SDK provides several helper functions to ease the configuration for third-party libraries. They are located under core folder.
createMicrosoftGraphClientWithCredential
, createMicrosoftGraphClient
and MsGraphAuthProvider
help to create authenticated Graph instance. These are now deprecated, we recommend you to use Microsoft Graph SDKs instead.
getTediousConnectionConfig
returns a tedious connection config. This API is now deprecated, we recommend you compose your own Tedious configuration for better flexibility.
Required configuration:
API will throw ErrorWithCode
if error happens. Each ErrorWithCode
contains error code and error message.
For example, to filter out specific error, you could use the following check:
try {
const authConfig: TeamsUserCredentialAuthConfig = {
clientId: process.env.REACT_APP_CLIENT_ID,
initiateLoginEndpoint: process.env.REACT_APP_START_LOGIN_PAGE_URL,
};
const credential = new TeamsUserCredential(authConfig);
await credential.login("User.Read");
} catch (err: unknown) {
if (err instanceof ErrorWithCode && err.code !== ErrorCode.ConsentFailed) {
throw err;
} else {
// Silently fail because user cancels the consent dialog
return;
}
}
And if credential instance is used in other library like Microsoft Graph, it's possible that error is catched and transformed.
try {
const authConfig: TeamsUserCredentialAuthConfig = {
clientId: process.env.REACT_APP_CLIENT_ID,
initiateLoginEndpoint: process.env.REACT_APP_START_LOGIN_PAGE_URL,
};
const credential = new TeamsUserCredential(authConfig);
const authProvider = new TokenCredentialAuthenticationProvider(credential, {
scopes: ["User.Read"],
});
const graphClient = Client.initWithMiddleware({ authProvider: authProvider });
const profile = await graphClient.api("/me").get();
} catch (err: unknown) {
// ErrorWithCode is handled by Graph client
if (err instanceof GraphError && err.code?.includes(ErrorCode.UiRequiredError)) {
this.setState({
showLoginBtn: true,
});
}
}
The following sections provide several code snippets covering some of the most common scenarios, including:
Use createMicrosoftGraphClientWithCredential
. Thie API is now deprecated, we recommend you to use Client
and TokenCredentialAuthenticationProvider
from Microsoft Graph SDKs (@microsoft/microsoft-graph-client
) instead.
const authConfig: TeamsUserCredentialAuthConfig = {
clientId: process.env.REACT_APP_CLIENT_ID,
initiateLoginEndpoint: process.env.REACT_APP_START_LOGIN_PAGE_URL,
};
const teamsUserCredential = new TeamsUserCredential(authConfig);
// Put login code in a call-to-action callback function to avoid browser blocking automatically showing up pop-ups.
await teamsUserCredential.login(["User.Read"]); // Login with scope
try {
const graphClient = createMicrosoftGraphClientWithCredential(teamsUserCredential, ["User. Read"]); // Initializes MS Graph SDK using our MsGraphAuthProvider
const profile = await graphClient.api("/me").get();
} catch (err: unknown) {
// ErrorWithCode is handled by Graph client
if (err instanceof GraphError && err.code?.includes(ErrorCode.UiRequiredError)) {
// Need to show login button to ask for user consent.
}
}
Use axios
library to make HTTP request to Azure Function.
async function callFunction() {
const authConfig: TeamsUserCredentialAuthConfig = {
clientId: process.env.REACT_APP_CLIENT_ID,
initiateLoginEndpoint: process.env.REACT_APP_START_LOGIN_PAGE_URL,
};
const teamsUserCredential = new TeamsUserCredential(authConfig);
const accessToken = await teamsUserCredential.getToken(""); // Get SSO token
const endpoint = "https://YOUR_API_ENDPOINT";
const response = await axios.default.get(endpoint + "/api/" + functionName, {
headers: {
authorization: "Bearer " + accessToken.token,
},
});
return response.data;
}
Use tedious
library to access SQL and leverage DefaultTediousConnectionConfiguration
that manages authentication.
Apart from tedious
, you can also compose connection config of other SQL libraries based on the result of sqlConnectionConfig.getConfig()
.
The tedious
library is now deprecated, we recommend you compose your own Tedious configuration for better flexibility.
// Equivalent to:
// const sqlConnectConfig = new DefaultTediousConnectionConfiguration({
// sqlServerEndpoint: process.env.SQL_ENDPOINT,
// sqlUsername: process.env.SQL_USER_NAME,
// sqlPassword: process.env.SQL_PASSWORD,
// });
const teamsfx = new TeamsFx();
// if there's only one SQL database
const config = await getTediousConnectionConfig(teamsfx);
// if there are multiple SQL databases
const config2 = await getTediousConnectionConfig(teamsfx, "your database name");
const connection = new Connection(config);
connection.on("connect", (error) => {
if (error) {
console.log(error);
}
});
const appAuthConfig: AppCredentialAuthConfig = {
authorityHost: process.env.M365_AUTHORITY_HOST,
clientId: process.env.M365_CLIENT_ID,
tenantId: process.env.M365_TENANT_ID,
certificateContent: "PEM-encoded key certificate",
};
const appCredential = new AppCredential(appAuthConfig);
const token = appCredential.getToken();
Add TeamsBotSsoPrompt
to dialog set.
const { ConversationState, MemoryStorage } = require("botbuilder");
const { DialogSet, WaterfallDialog } = require("botbuilder-dialogs");
const {
TeamsBotSsoPrompt,
OnBehalfOfCredentialAuthConfig,
TeamsBotSsoPromptSettings,
} = require("@microsoft/teamsfx");
const convoState = new ConversationState(new MemoryStorage());
const dialogState = convoState.createProperty("dialogState");
const dialogs = new DialogSet(dialogState);
const TeamsBotSsoPromptId = "TEAMS_BOT_SSO_PROMPT";
const settings: TeamsBotSsoPromptSettings = {
scopes: ["User.Read"],
timeout: 900000,
endOnInvalidMessage: true,
};
const authConfig: OnBehalfOfCredentialAuthConfig = {
authorityHost: process.env.M365_AUTHORITY_HOST,
clientId: process.env.M365_CLIENT_ID,
tenantId: process.env.M365_TENANT_ID,
clientSecret: process.env.M365_CLIENT_SECRET,
};
const loginUrl = process.env.INITIATE_LOGIN_ENDPOINT;
const ssoPrompt = new TeamsBotSsoPrompt(authConfig, loginUrl, TeamsBotSsoPromptId, settings);
dialogs.add(ssoPrompt);
dialogs.add(
new WaterfallDialog("taskNeedingLogin", [
async (step) => {
return await step.beginDialog("TeamsBotSsoPrompt");
},
async (step) => {
const token = step.result;
if (token) {
// ... continue with task needing access token ...
} else {
await step.context.sendActivity(`Sorry... We couldn't log you in. Try again later.`);
return await step.endDialog();
}
},
])
);
const teamsfx = new TeamsFx();
// Create an API Key auth provider. Following auth providers are also available:
// BearerTokenAuthProvider, BasicAuthProvider, CertificateAuthProvider
const authProvider = new ApiKeyProvider(
"your_api_key_name",
teamsfx.getConfig("YOUR_API_KEY_VALUE"), // This reads the value of YOUR_API_KEY_VALUE environment variable
ApiKeyLocation.Header
);
// Create an API client using above auth provider
// You can also implement AuthProvider interface and use it here
const apiClient = createApiClient(
teamsfx.getConfig("YOUR_API_ENDPOINT"), // This reads YOUR_API_ENDPOINT environment variable
authProvider
);
// Send a GET request to "relative_api_path"
const response = await apiClient.get("relative_api_path");
You can set custome log level and redirect outputs when using this library. Logging is turned off by default, you can turn it on by setting log level.
When log level is set, logging is enabled. It prints log information to console by default.
Set log level using the snippet below:
// Only need the warning and error messages.
setLogLevel(LogLevel.Warn);
You can redirect log output by setting custom logger or log function.
setLogLevel(LogLevel.Info);
// Set another logger if you want to redirect to Application Insights in Azure Function
setLogger(context.log);
Please note that log function will not take effect if you set a custom logger.
setLogLevel(LogLevel.Info);
// Only log error message to Application Insights in bot application.
setLogFunction((level: LogLevel, message: string) => {
if (level === LogLevel.Error) {
this.telemetryClient.trackTrace({
message: message,
severityLevel: Severity.Error,
});
}
});
You can pass custom config when creating TeamsFx
instance to override default configuration or set required fields when environment variables are missing.
If you have created tab project using VS Code toolkit, the following config values will be used from pre-configured environment variables:
If you have created Azure Function / Bot project using VS Code toolkit, the following config values will be used from pre-configured environment variables:
If you are using the version of SDK that has loadConfiguration()
, you can follow these steps to upgrade to the latest SDK version.
loadConfiguration()
, use the specific auth config classes to customize the settings for each credential type. For example, use AppCredentialAuthConfig
for AppCredential
, OnBehalfOfUserCredentialAuthConfig
for OnBehalfOfUserCredential
, and TeamsUserCredentialAuthConfig
for TeamsUserCredential
.new TeamsUserCredential()
with new TeamsUserCredential(authConfig)
.new M365TenantCredential()
with new AppCredential(authConfig)
.new OnBehalfOfUserCredential(ssoToken)
with new OnBehalfOfUserCredential(authConfig)
.Also see Credential for furthur description.
CloudAdapter
From botbuilder@4.16.0
, BotFrameworkAdapter
is deprecated, and CloudAdapter
is recommended to be used instead. You can import ConversationBot
from BotBuilderCloudAdapter
to use the latest SDK implemented with CloudAdapter
.
Install @microsoft/teamsfx @^2.2.0
, botbuilder @^4.18.0
, (and @types/node @^18.0.0
for TS projects) via npm install
as follows.
npm install @microsoft/teamsfx
npm install botbuilder
// For TS projects only
npm install --save-dev @types/node
Update the import of ConversationBot
and create a new ConversationBot
as follows.
import { HelloWorldCommandHandler } from "../helloworldCommandHandler";
import { BotBuilderCloudAdapter } from "@microsoft/teamsfx";
import ConversationBot = BotBuilderCloudAdapter.ConversationBot;
import config from "./config";
export const commandBot = new ConversationBot({
// The bot id and password to create CloudAdapter.
// See https://aka.ms/about-bot-adapter to learn more about adapters.
adapterConfig: {
MicrosoftAppId: config.botId,
MicrosoftAppPassword: config.botPassword,
MicrosoftAppType: "MultiTenant",
},
command: {
enabled: true,
commands: [new HelloWorldCommandHandler()],
},
});
If the project is using restify
to create a server, please add the following line after restify.createServer()
.
server.use(restify.plugins.bodyParser());
The complete code will be like
// Create HTTP server.
const server = restify.createServer();
server.use(restify.plugins.bodyParser());
server.listen(process.env.port || process.env.PORT || 3978, () => {
console.log(`\nApp Started, ${server.name} listening to ${server.url}`);
});
If the project is using express
to create a server, please add the following line after express()
.
expressApp.use(express.json());
The complete code will be like
// Create HTTP server.
const expressApp = express();
expressApp.use(express.json());
const server = expressApp.listen(process.env.port || process.env.PORT || 3978, () => {
console.log(`\nBot Started, ${expressApp.name} listening to`, server.address());
});
If the project has responseWrapper.ts
, please update the class responseWrapper
to the class below.
import { Response } from "botbuilder";
// A wrapper to convert Azure Functions Response to Bot Builder's Response.
export class ResponseWrapper implements Response {
socket: any;
originalResponse?: any;
headers?: any;
body?: any;
constructor(functionResponse?: { [key: string]: any }) {
this.socket = undefined;
this.originalResponse = functionResponse;
}
end(...args: any[]) {
// do nothing since res.end() is deprecated in Azure Functions.
}
header(name: string, value: any) {
this.headers[name] = value;
}
send(body: any) {
// record the body to be returned later.
this.body = body;
this.originalResponse.body = body;
}
status(status: number) {
// call Azure Functions' res.status().
return this.originalResponse?.status(status);
}
}
Please take a look at the Samples project for detailed examples on how to use this library.
The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the repository. There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft's privacy statement. Our privacy statement is located at https://go.microsoft.com/fwlink/?LinkID=824704. You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices.
This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact opencode@microsoft.com with any additional questions or comments.
There are many ways in which you can participate in the project, for example:
If you are interested in fixing issues and contributing directly to the code base, please see the Contributing Guide.
Please do not report security vulnerabilities through public GitHub issues.
Instead, please report them to the Microsoft Security Response Center (MSRC) at https://msrc.microsoft.com/create-report.
If you prefer to submit without logging in, send email to secure@microsoft.com. If possible, encrypt your message with our PGP key; please download it from the the Microsoft Security Response Center PGP Key page.
You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at microsoft.com/msrc.
This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft trademarks or logos is subject to and must follow Microsoft's Trademark & Brand Guidelines. Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. Any use of third-party trademarks or logos are subject to those third-party's policies.
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the MIT license.
FAQs
Microsoft Teams Framework for Node.js and browser.
We found that @microsoft/teamsfx demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 4 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
Security News
Socket researchers uncover a malicious npm package posing as a tool for detecting vulnerabilities in Etherium smart contracts.
Security News
Research
A supply chain attack on Rspack's npm packages injected cryptomining malware, potentially impacting thousands of developers.
Research
Security News
Socket researchers discovered a malware campaign on npm delivering the Skuld infostealer via typosquatted packages, exposing sensitive data.