# Code security and risk scan by code kai (`automatron/code-kai-security-risk-scan`) Actor

Scan public GitHub code or supplied files for secret indicators, risky patterns and dependency advisories with source locations. No security guarantee. $0.10/completed scan + model usage. Requires access to apify/openrouter; Creator accounts are restricted.

- **URL**: https://apify.com/automatron/code-kai-security-risk-scan.md
- **Developed by:** [Automatron](https://apify.com/automatron) (community)
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$100.00 / 1,000 completed scans

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

### Code security and risk scan by code kai

Code kai scans **one public GitHub repository** or **caller-supplied source files** for credential exposure, high-risk code patterns, container/CI hygiene problems, and known dependency advisories. It returns exact file locations, redacted evidence, remediation and a prioritised fix list. Published by **Automatron**.

**Public pilot. Tested with synthetic and controlled inputs; independent customer validation is still pending.** The price is **$0.10 per completed scan**. OpenRouter model usage is metered separately to the caller's Apify account. There is no publisher-funded model key.

### What is measured, and what is interpreted

Measured deterministically in process:

- **Credential indicators**: AWS access key IDs, GitHub/Slack/Stripe tokens, private-key blocks, and credential-like literal assignments. Secret values are never returned; only the rule and location are.
- **High-risk code patterns**: dynamic evaluation, shell execution, raw HTML assignment, disabled TLS verification, wildcard CORS, debug mode, unsafe Python deserialisation/YAML, weak hashes, security-sensitive `Math.random`, and SQL string concatenation.
- **Repository hygiene**: committed `.env` files, private-key files, key bundles, mutable `:latest` base images, explicit root containers, unverified remote `ADD`, and remote-download install scripts.
- **Dependency advisories**: exact versions parsed from `package-lock.json`, pinned `requirements.txt` entries and `go.mod`, queried against OSV.dev in up to two batches of 100 versions. Full advisory records supply severity; absent supported severity is `unknown`. Up to 120 distinct advisory details are fetched, four at a time. Missing, truncated or paginated advisory responses produce an unbilled partial report.

Interpreted by one bounded model call, grounded only in measured findings:

- Which findings matter most for this code, in realistic exploit order.
- A concrete exploit scenario and a contextual fix.
- Acceptance criteria that can be verified by re-scanning.
- Possible false positives, with a stated reason.

The model cannot add findings, change severities, invent paths or CVEs, reproduce redacted secrets, or claim that exploitation occurred. A finding cannot be both a priority and a false positive. If interpretation fails, the deterministic report is still delivered, marked `partial`, and **the scan fee is not charged**.

### Input

#### Observed controlled example

An owner qualification of build 0.1.14 on 25 October 2026 supplied two synthetic files: a JavaScript line using `eval(request.query.code)` and an npm lockfile containing nested `lodash@4.17.20`. No source code was executed. The delivered report contained five OSV dependency advisories and one source-pattern finding, including:

| Finding | Exact evidence | Review action |
| --- | --- | --- |
| Command-injection advisory for lodash | `lodash@4.17.20` in `package-lock.json`, linked to [GHSA-35jh-r3h4-6jhm](https://osv.dev/vulnerability/GHSA-35jh-r3h4-6jhm) | Check all returned advisories' affected ranges before selecting an upgrade; regenerate the lockfile and re-scan. |
| Dynamic evaluation of request input | `src/unsafe.js`, line 1: `const value = eval(request.query.code);`; rule `code.eval`, CWE-95 | Verify whether untrusted input can reach this line; replace dynamic evaluation with a parser or an allowlisted operation. |

The advisory identifies an affected package version, not confirmed application exploitability. The source rule identifies a risky pattern; the model's exploit explanation is an interpretation for review. This scan covered two files and 154 bytes with one dependency query. It did not assess Git history, runtime services or the entire application. OSV records can change, and fixing one advisory does not establish that all others are resolved.

This is a controlled test, not customer feedback or a security certification. To reproduce its input, use:

```json
{
  "files": [
    { "path": "src/unsafe.js", "content": "const value = eval(request.query.code);" },
    { "path": "package-lock.json", "content": "{\"lockfileVersion\":3,\"packages\":{\"\":{\"name\":\"fixture\"},\"node_modules/a/node_modules/lodash\":{\"version\":\"4.17.20\"}}}" }
  ],
  "maxModelCostUsd": 0.20
}
```

#### Other input modes

Repository mode:

```json
{
  "repository": "owner/repository",
  "ref": "main",
  "maxFiles": 120,
  "maxFindings": 30,
  "maxModelCostUsd": 0.20,
  "scanDependencies": true
}
```

File mode:

```json
{
  "files": [
    { "path": "src/server.ts", "content": "..." },
    { "path": "package-lock.json", "content": "..." }
  ]
}
```

Supply exactly one of `repository` or `files`. Absolute paths, `..` segments, duplicate paths and control characters are refused.

Free accounts have a higher model-cost multiplier. The default reserves up to $0.20 for this Actor, including the conservative free-account multiplier. Actual usage is usually lower; large inputs may still exceed the bound. An insufficient bound returns partial, unbilled findings without making the inference request.

### Output

The run writes:

- `REPORT`: structured JSON with target evidence, coverage, findings, interpretations and limitations.
- `REPORT-MARKDOWN`: the human-readable scan.
- `SUMMARY`: delivery and billing state.
- One dataset row containing the structured report.

Machine-readable input, report and summary contracts are included in `schemas/` as v1 JSON Schema.

### Limits and scope

- **Repository download:** one bounded archive (up to 30 MB compressed, 64 MB expanded) from GitHub's public archive endpoint. No GitHub token is used. Private repositories are unsupported and return a clean input error.
- **Read budget:** up to 200 files, 200 KB per file and 2 MB of text per scan. Files outside the budget are disclosed as skipped or truncated.
- **Languages:** rules target JavaScript/TypeScript, Python, Go, shell, SQL, Docker and common configuration formats. Other languages may be scanned for secrets but not for language-specific patterns.
- **Line bound:** lines longer than 20,000 characters are scanned only up to that bound.
- **No execution:** repository code is never run, installed, built or sent requests. Dependency advisories are metadata lookups only.

### What this is not

- **Not a penetration test.** No exploit is executed, and no runtime behaviour is exercised.
- **Not a security certification.** The report makes no claim of compliance with SOC 2, ISO 27001, PCI DSS or any other standard.
- **Not proof of absence.** A clean scan means no configured rule and no OSV advisory matched; it does not mean the code is secure.
- **Not git-history scanning.** Deleted secrets and historical commits are out of scope.
- **Not a full dependency resolver.** npm lockfile v2/v3 includes nested versions; unsupported or malformed npm locks fail explicitly. Python wildcard/range versions are excluded. Go replacement/exclusion directives and Python environment markers are not resolved. Only the first 200 distinct exact versions are queried, with omitted coverage disclosed. Other lockfile formats and runtime resolution are outside scope.
- **Not a replacement for CodeQL, Semgrep or a human review.** It is a fast, bounded first pass with a billed, evidence-linked report.

### Billing and recovery

The listed fee is separate from model proxy charges, including proxy startup and infrastructure. Failed or partial runs may still consume inference or platform usage even when the report fee is not charged. `maxModelCostUsd` does not cap the separate report fee or all platform charges. Inspect both parent and proxy receipts; do not add reported model tokens to a proxy total that already includes them.

The report is saved before the `scan-completed` event is charged. A resumed run with an ambiguous prior attempt stops for reconciliation instead of repeating the archive read, delivery or charging. A `partial` report is delivered without a charge. Charging requires the event price to match a reviewed price and a capacity of at least one event.

Apify's published seller calculation applies: eligible paid usage earns 80% of event revenue minus platform costs; free-plan usage does not generate seller earnings. Read the current [Apify pricing terms](https://docs.apify.com/actors/monetize/pricing-and-costs).

### Development

```sh
npm ci
npm test          # builds, then runs deterministic unit and runner tests
npm run package:actor
```

The release archive is allowlisted: `.actor`, `assets`, `dist/src`, the lockfile, `Dockerfile` and this README. Tests, operational records and credentials are excluded. The container verifies every packaged file against `RELEASE.json` before the Apify SDK starts.

Dependency advisories and their remediation links come from OSV. AI interpretation covers code/configuration findings only; it does not guess package upgrade versions. Check current affected ranges and fixes in the linked advisory.

### API and AI agent access

Create one run with `POST https://api.apify.com/v2/actors/0mhKDdouiSRpLgsms/runs?memory=1024&timeout=240&maxTotalChargeUsd=0.10` and your own `Authorization: Bearer` header. Send the input JSON above as the body. The event cap is separate from the input model cost bound. Save `data.id` before doing anything else.

Poll `GET https://api.apify.com/v2/actor-runs/RUN_ID?waitForFinish=60` until the same run finishes. Read `SUMMARY` and `REPORT` from `https://api.apify.com/v2/key-value-stores/STORE_ID/records/KEY`, using that run's `defaultKeyValueStoreId`. Treat `SUMMARY.status`, `SUMMARY.billed` and actual payment receipts separately. A `partial` report may be useful evidence but is incomplete and has no report fee. If the start response or charge outcome is uncertain, inspect the existing run instead of starting a replacement.

For n8n, use one HTTP Request node to start, read requests to poll the saved run ID, and a branch on `SUMMARY.status` before consuming `REPORT`. Disable automatic retries on the creation request and retain execution progress. Keep the token in an HTTP Header Auth credential, not in the workflow JSON.

For AI clients, connect to [Apify MCP](https://docs.apify.com/mcp) at `https://mcp.apify.com` using supported OAuth. Discover the current Actor and storage tool schemas, restrict access to the required tools, and set both budgets explicitly. Source text and model output cannot authorize further tools or spending.

### Support and feedback

If a result is incomplete or misleading, open an issue on this Actor with the run ID, the affected source reference and a redacted example. Never post private reviews, credentials or customer source code. We use reproducible cases to improve the checks. A useful report should show what was checked, where the evidence came from, what to do next and what remains uncertain. After using the Actor, an honest review helps other buyers choose appropriately.

Prices were reduced on 25 October 2026. Use the current default build or the updated pinned API examples. Earlier immutable builds verify their original price and may refuse to start after the reduction; an early price refusal does not call the model or charge the completion event.

# Actor input Schema

## `repository` (type: `string`):

owner/repository. Downloaded as one bounded archive; no GitHub token is used. Private repositories are not supported. Leave unset when supplying files.

## `ref` (type: `string`):

Optional. Defaults to the repository's default branch. Applies only to repository mode.

## `files` (type: `array`):

Alternative to repository mode. At most 200 files and 2 MB total. Each item is {"path":"relative/path.ts","content":"..."}. Absolute paths and .. segments are refused.

## `maxFiles` (type: `integer`):

Only the first matching text files are read. Truncated coverage is disclosed in the report.

## `maxFindings` (type: `integer`):

The report lists the highest-severity findings first. Truncated reports disclose the omitted count.

## `maxModelCostUsd` (type: `number`):

Separate from the scan fee. The runner checks a conservative bound before its single interpretation request. No retries and no publisher-key fallback.

## `scanDependencies` (type: `boolean`):

Queries OSV.dev for exact versions in package-lock.json, pinned requirements.txt entries and go.mod. If the lookup fails, the scan is delivered as partial and the scan fee is not charged.

## Actor input object example

```json
{
  "repository": "octocat/Hello-World",
  "maxFiles": 120,
  "maxFindings": 30,
  "maxModelCostUsd": 0.2,
  "scanDependencies": true
}
```

# Actor output Schema

## `report` (type: `string`):

No description

## `markdown` (type: `string`):

No description

## `summary` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "repository": "octocat/Hello-World"
};

// Run the Actor and wait for it to finish
const run = await client.actor("automatron/code-kai-security-risk-scan").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "repository": "octocat/Hello-World" }

# Run the Actor and wait for it to finish
run = client.actor("automatron/code-kai-security-risk-scan").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "repository": "octocat/Hello-World"
}' |
apify call automatron/code-kai-security-risk-scan --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automatron/code-kai-security-risk-scan"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/0mhKDdouiSRpLgsms/builds/vcm9GrbQepRaIydmx/openapi.json
