CtrlK
BlogDocsLog inGet started
Tessl Logo

endor-ai-sast

Fetch and display AI-powered SAST findings from the Endor Labs platform. Default path is summary-only (aggregated counts + clusters); full masked listing runs only when the user asks to drill down (speed and token use). Use when the user says "AI SAST results", "AI SAST findings", "AI static analysis", "endor ai sast", "show AI SAST", or wants pre-computed AI-driven code security findings. Do NOT use for running a new SAST scan (/endor-sast), viewing general findings (/endor-findings), or explaining a specific CVE (/endor-explain).

72

Quality

88%

Does it follow best practices?

Impact

No eval scenarios have been run

SecuritybySnyk

Advisory

Suggest reviewing before use

SKILL.md
Quality
Evals
Security

Endor Labs AI SAST Analysis

Fetch AI-powered static analysis security findings using pre-computed data from the Endor Labs platform.

Prerequisites

  • Endor Labs authenticated (run /endor-setup if not)

Workflow

Two phases (default: Phase 1 only):

PhaseAPI callsPurpose
1 — Summary3a + 3b onlySeverity table + cluster lines. Minimizes latency and token use. Do not run 3c.
2 — Detail3c (on user request)spec.explanation, per-finding locations, data flow, filtered tables. Run only what the user asked for; prefer a tighter filter over loading the full list when possible.

Step 1: Resolve Namespace

Before making ANY endorctl api call, resolve the namespace.

export ENDOR_NAMESPACE="${ENDOR_NAMESPACE:-$(grep -E '^ENDOR_NAMESPACE:' ~/.endorctl/config.yaml 2>/dev/null | awk '{print $2}' | tr -d '"')}"
echo "ENDOR_NAMESPACE=$ENDOR_NAMESPACE"

If empty, run /endor-setup to authenticate and set the namespace.

Step 2: Find the Project UUID

Get the git remote URL, normalize it to HTTPS format, then query for the project. Only run this after Step 1 succeeds.

RAW_URL=$(git remote get-url origin 2>/dev/null)
# Normalize SSH URLs (git@github.com:org/repo.git) to HTTPS (https://github.com/org/repo.git)
if echo "$RAW_URL" | grep -q '^git@'; then
  GIT_URL="https://$(echo "$RAW_URL" | sed 's|^git@||; s|:|/|')"
else
  GIT_URL="$RAW_URL"
fi
npx -y endorctl api list --resource Project -n $ENDOR_NAMESPACE \
  --filter "spec.git.http_clone_url=='$GIT_URL'" \
  --field-mask="uuid,meta.name" 2>&1 | tee /tmp/endor_list_project_output.txt

For CLI field paths and parsing gotchas, read references/cli-parsing.md.

Run this command ONCE with the normalized URL. Do NOT retry with URL variations. If the project is not found, see Error Handling.

Step 3: Fetch AI SAST Findings

Use the same base filter on every call below (advanced list API; grouping pattern aligns with /endor-api / endorctl api list filter syntax).

Base filter (repeat in 3a, 3b, and 3c):

'context.type == CONTEXT_TYPE_MAIN and spec.project_uuid == "{PROJECT_UUID}" and spec.method == SYSTEM_EVALUATION_METHOD_DEFINITION_AI_SAST'

Step 3a: Severity summary (run first — fast)

One grouped query returns counts per spec.level without pulling explanations or large payloads:

npx -y endorctl api list -r Finding -n $ENDOR_NAMESPACE \
  -f 'context.type == CONTEXT_TYPE_MAIN and spec.project_uuid == "{PROJECT_UUID}" and spec.method == SYSTEM_EVALUATION_METHOD_DEFINITION_AI_SAST' \
  --group-aggregation-paths "spec.level" \
  | tee /tmp/endor_ai_sast_summary.txt

Use stdout-only piping to tee (do not use 2>&1) so the saved file stays pure JSON for jq. Endorctl writes upgrade notices to stderr.

Short-circuit: If the grouped response has no findings (total count is 0), respond with exactly: "No AI SAST findings are available for this project at this moment." — no further explanation. Do not run Steps 3b or 3c (there is nothing to drill into).

Total count (for the short-circuit check and the summary Total row):

jq '[(.group_response.groups // {}) | to_entries[] | .value.aggregation_count.count] | add // 0' /tmp/endor_ai_sast_summary.txt

Optional: map enum levels to counts for the summary table (parse group_response):

jq -r '.group_response.groups // {} | to_entries[] | (.key | fromjson | .[] | select(.key=="spec.level") | .value) as $lvl | "\($lvl) \(.value.aggregation_count.count)"' /tmp/endor_ai_sast_summary.txt

Step 3b: Vulnerability clusters (fast — only if Step 3a shows at least one finding)

Two grouped queries replace parsing the full listing for cluster counts, distinct files per cluster, and severity mix per cluster (for titles like [Critical/High]). Run both after 3a succeeds.

3b(i) — Total findings and distinct file paths per meta.description:

npx -y endorctl api list -r Finding -n $ENDOR_NAMESPACE \
  -f 'context.type == CONTEXT_TYPE_MAIN and spec.project_uuid == "{PROJECT_UUID}" and spec.method == SYSTEM_EVALUATION_METHOD_DEFINITION_AI_SAST' \
  --group-aggregation-paths "meta.description" \
  --group-unique-count-paths "spec.dependency_file_paths" \
  | tee /tmp/endor_ai_sast_cluster_counts.txt

Per-cluster finding count: aggregation_count.count. Distinct locations: unique_counts.spec.dependency_file_paths.count.

3b(ii) — Counts per meta.description × spec.level (derive highest severity present and multi-level labels for Step 4b):

npx -y endorctl api list -r Finding -n $ENDOR_NAMESPACE \
  -f 'context.type == CONTEXT_TYPE_MAIN and spec.project_uuid == "{PROJECT_UUID}" and spec.method == SYSTEM_EVALUATION_METHOD_DEFINITION_AI_SAST' \
  --group-aggregation-paths "meta.description" \
  --group-aggregation-paths "spec.level" \
  | tee /tmp/endor_ai_sast_cluster_severity.txt

Each group_response.groups key is a JSON array of {key, value} pairs (description and level). Sum aggregation_count.count over entries that share the same meta.description to match 3b(i) totals. For each description, note which FINDING_LEVEL_* values appear to sort clusters and to label [Critical], [High], [Critical/High], etc.

Step 3c: Full findings (Phase 2 only — when the user asks for detail)

Do not run in the default flow. Run 3c only after the user chooses a drill-down (see Step 4d). This call pulls large spec.explanation text; keep it scoped to what they asked for.

Default 3c command (entire AI SAST set — use only if they want everything, e.g. "load all findings" or "full report"):

npx -y endorctl api list -r Finding -n $ENDOR_NAMESPACE \
  -f 'context.type == CONTEXT_TYPE_MAIN and spec.project_uuid == "{PROJECT_UUID}" and spec.method == SYSTEM_EVALUATION_METHOD_DEFINITION_AI_SAST' \
  --field-mask meta.description,spec.explanation,spec.dependency_file_paths,spec.level \
  --list-all \
  | tee /tmp/endor_sast_findings_output.txt

Prefer narrower filters (append to the base filter with and ...) to cut volume and tokens:

User requestAdd to filter (examples)
Critical onlyand spec.level==FINDING_LEVEL_CRITICAL
High and Criticaland spec.level in [FINDING_LEVEL_CRITICAL, FINDING_LEVEL_HIGH]
One cluster / CWEand meta.description contains "SQL Injection" (match substring of the full meta.description string)
One fileand spec.dependency_file_paths contains "path/to/file.cs" (if the API supports contains on that field; otherwise run full 3c and filter in presentation)

Re-run 3c when the user’s next question needs different fields or a different filter; do not load the full list preemptively.

Step 4: Present Results

Phase 1 (default): Present 4a and 4b from 3a and 3b only. Stop after 4d (drill-down prompt) — do not run 3c, do not show 4c unless the user continues to Phase 2.

Phase 2: After the user answers 4d (or explicitly asks for detail), run 3c as needed, then 4c / full drill-down content. The goal is to answer "what should I worry about?" first with minimal API and context size, then pay for detail on demand.

4a: Severity Breakdown

Build the summary count table from Step 3a (map FINDING_LEVEL_* to Critical / High / Medium / Low). If you already showed counts from 3a, keep this section brief:

## AI SAST Findings Summary

| Severity | Count |
|----------|-------|
| Critical | X     |
| High     | X     |
| Medium   | X     |
| Low      | X     |
| **Total**| **X** |

4b: Actionable Groups

Build clusters from Step 3b: use meta.description strings from the grouped responses (not the full Step 3c list). 3b(i) supplies finding counts and distinct file counts (N findings across M files). 3b(ii) supplies which severity levels appear per description — map to short severity labels for each cluster (sort by highest severity present, then by count).

Short titles: Use concise names in the output, not full CWE descriptions. Map verbose meta.description values to short labels:

meta.description containsShort title
SQL CommandSQL Injection
Cross-site Scripting / Web Page GenerationXSS
Code Injection / Generation of CodeCode Injection
Path Traversal / Pathname to a Restricted DirectoryPath Traversal
Authorization Bypass Through User-Controlled KeyAuthorization Bypass (IDOR)
Missing Authorization / Missing AuthenticationMissing Auth
Sensitive Information into LogSensitive Info in Logs
Hard-coded Credentials / Hard-coded CryptographicHard-coded Credentials
Cleartext StorageCleartext Storage
Cleartext TransmissionCleartext Transmission
Exposure of Sensitive InformationInfo Disclosure
XML External EntityXXE
Server-Side Request ForgerySSRF
NoSQL / MongoDBNoSQL Injection
Cryptographic Signature / Password HashWeak Cryptography
Deserialization of Untrusted DataInsecure Deserialization
Open Redirect / URL RedirectionOpen Redirect
Rate LimitRate Limit Bypass
Privilege Management / Incorrect AuthorizationBroken Access Control
Denial of Service / Resource Exhaustion / Resource ConsumptionDoS
Improper Handling of Exceptional Conditions / NULL PointerError Handling
Improper Input ValidationInput Validation
Business LogicBusiness Logic Flaw
Unhandled.*Error / Unhandled.*ExceptionUnhandled Error
Insecure DesignInsecure Design
Improper VerificationImproper Verification
(anything else)Use the parenthesized short name if present, otherwise use the full title

Only show clusters with 2+ findings. Sort by highest severity in the group, then by count descending. For each cluster show:

### Vulnerability Clusters

- **SQL Injection** (6 findings across 5 files) [Critical] — use parameterized queries across all SQL operations
- **XSS** (8 findings across 7 files) [Critical/High] — audit all uses of bypassSecurityTrustHtml and innerHTML
- **Authorization Bypass (IDOR)** (5 findings across 4 files) [High] — enforce server-side ownership checks in middleware

Remediation suggestions (Phase 1): Use the generic mapping below — one line per cluster. Do not run 3c just to tailor text. After Phase 2, you may refine using spec.explanation from 3c.

ClusterRemediation
SQL Injectionuse parameterized queries across all SQL operations
XSSaudit all uses of bypassSecurityTrustHtml and innerHTML; use Angular sanitization
Code Injectionremove eval/safeEval usage; use safe alternatives
Path Traversalvalidate and canonicalize file paths; reject .. sequences
Authorization Bypass (IDOR)enforce server-side ownership checks in middleware
NoSQL Injectionuse typed query builders; never concatenate user input into $where clauses
Missing Authadd authentication/authorization middleware to exposed endpoints
Sensitive Info in Logssanitize error objects before logging; avoid console.log of raw errors
Hard-coded Credentialsmove secrets to environment variables or a vault
Cleartext Storage / Transmissionuse httpOnly secure cookies instead of localStorage
Info Disclosurerestrict endpoint access and filter sensitive fields from responses
SSRFvalidate URL scheme and host against an allowlist before server-side fetch
XXEdisable external entity processing in XML parser configuration
Rate Limit Bypassuse trusted client IP (not X-Forwarded-For) or validate proxy headers
Open Redirectvalidate redirect targets against an allowlist of trusted domains
Weak Cryptographyuse bcrypt/scrypt for passwords; verify JWT signatures server-side
Insecure Deserializationuse safe loaders (e.g., yaml.safeLoad); validate input schema before parsing
DoSadd input size limits and validation before resource allocation
Broken Access Controlverify user roles/permissions server-side on every request
Error Handlingadd null/undefined checks and error boundaries; validate assumptions before dereferencing
Input Validationvalidate and sanitize all user-controlled input at system boundaries
Business Logic Flawadd server-side validation for business rules; don't trust client-supplied IDs or amounts
Unhandled Errorwrap I/O operations in try/catch; handle missing files and failed calls gracefully
Insecure Designenforce resource limits and validate contracts before processing
Improper Verificationverify signatures and integrity server-side; don't trust client-decoded tokens

After the multi-finding clusters, add a single rollup line for all single-finding types:

- *+ N other finding types with 1 finding each (use drill-down to explore)*

In Phase 2, use spec.explanation to sharpen remediation if it contradicts the generic line.

4c: Critical Findings Detail (Phase 2 — requires 3c first)

Only after the user asks for per-finding detail (e.g. Critical table, file list, explanations). Run 3c with and spec.level==FINDING_LEVEL_CRITICAL when they want Critical-only — do not pull the full finding set unless they ask.

Using Step 3c output, show a compact one-line-per-finding table for Critical severity when that was the ask (for other severities or clusters, filter 3c accordingly):

### Critical Findings

| # | Title | Location | Summary |
|---|-------|----------|---------|
  • Title: short title (use the same short title mapping from Step 4b, not the full CWE description)
  • Location: value of spec.dependency_file_paths
  • Summary: one-sentence summary extracted from spec.explanation (everything after ## Summary, truncated to the first sentence or ~150 characters)

Sort rows by vulnerability type (group related findings together).

Title/summary cross-check: If the spec.explanation summary clearly describes a different vulnerability class than meta.description suggests (e.g., meta.description says "SQL Injection" but the summary describes a MongoDB $where NoSQL injection), use the summary-derived type for the short title in the table. The summary is closer to the actual finding; meta.description can be a rough CWE category that doesn't match the specific issue.

Do NOT include the Data Flow column until the user asks for it (Phase 2). Data flow lives under spec.explanation (see 4d).

4d: End Phase 1 — Drill-Down Prompt (always show this after 4a + 4b)

Phase 1 ends here. Ask what to load next — do not run 3c until the user replies.

---
**Summary only so far** (no explanations or file-level detail loaded — fast / low tokens).

**What should we drill into?** Examples:
- "Critical findings table" → run **3c** with `spec.level==FINDING_LEVEL_CRITICAL`, then **4c**
- "High findings" → **3c** filtered to High (and Critical if they want)
- "Expand XSS cluster" → **3c** with `meta.description contains "Cross-site Scripting"` (match their CWE string from Phase 1)
- "Data flow for finding #3" → run **3c** (narrow filter if they named severity/cluster), locate the finding, paste Data Flow from `spec.explanation`
- "Full explanations for everything" → full **3c** with `--list-all` (expensive — confirm scope if counts are large)

Phase 2 — After the user chooses

  1. Run 3c with the smallest filter that satisfies the request.
  2. Present tables or verbatim fields from 3c output.

Full finding fields for drill-down:

  • Title: value of meta.description — copy verbatim
  • Finding Location: value of spec.dependency_file_paths
  • Severity: value of spec.level
  • Summary: copy verbatim from spec.explanation — everything after ## Summary up to (but not including) ## Data Flow
  • Data Flow: copy verbatim from spec.explanation — everything from ## Data Flow to the end, including all Stage and Location fields

For data source policy, read references/data-sources.md.

Error Handling

ErrorAction
Auth errorRun /endor-setup
License/permission errorInform user: "AI SAST requires an Endor Labs license. Visit app.endorlabs.com or contact your administrator."
Project not foundRun /endor-scan to onboard the project, then retry /endor-ai-sast
No findingsShow exact message: "No AI SAST findings are available for this project at this moment."
Repository
endorlabs/skills-ideas
Last updated
Created

Is this your skill?

If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.