---
title: "Run security scan"
method: POST
path: "/api/apps/{app_id}/security/scan"
---

# Run security scan

`POST /api/apps/{app_id}/security/scan`

<Info>This API is in beta. Endpoints, fields, and behavior may still change, so avoid depending on it in production.</Info>

Scans the app for security problems and returns the findings.

The response is the same shape as [Get security scan](/api-reference/get-security-scan), and which of two things you get depends on whether Base44 already has a current answer:

- If the last scan still matches the app, you get it straight back with `status` set to `up_to_date`, and the `X-Scan-Source` response header set to `cache`. Nothing is re-scanned.
- Otherwise a scan starts in the background and you get `status` set to `scanning` with the previous findings still in `result`, and `X-Scan-Source` set to `async`. Poll [Get security scan](/api-reference/get-security-scan) while `status` is `pending` or `scanning`, since both mean a scan is still going to settle.

So a 200 here does not mean a scan ran, and it does not mean the findings in the body are current. Read `status` and the `X-Scan-Source` header to tell the two apart.

A real scan reads the app's code and runs a language model over it, which takes a while and is why it runs in the background rather than on your connection. This endpoint is limited to 5 requests per minute.

<Note>Findings are only ever as fresh as the scan that produced them. On `out_of_date` the app has changed since, so treat the findings as a previous snapshot and run a new scan before acting on them.</Note>

<Warning>The response includes fields beyond the ones documented here. Don't rely on undocumented response fields, as they can change at any time.</Warning>

## Path parameters

- `app_id` string, required — ID of the app to scan.

## Query parameters

- `language` 'en' | 'ja' | 'de' | 'es' | 'fr' | 'pt' — Language to return generated text in, as a lowercase two-letter code. An unsupported value is rejected with a 422.

## Response `200`

The findings, or the state of the scan that just started.

- SecurityScanStatus — The state of an app's security scan, and its findings when it has any.
  - `status` string, required — Where the scan is. `up_to_date` means `result` reflects the app as it is now. `out_of_date` means the app changed since the last scan, so `result` is stale or absent. `none` means the app has never been scanned. `pending` means a scan is queued and `scanning` means one is running, and both can carry an earlier `result` while you wait. `scan_failed` means the last scan died, so run another.
  - `result` SecurityScanFindings, required — What a completed security scan found.
    - `analysis_summary` string, required — Plain-language summary of the scan.
    - `rls_recommendations` SecurityRlsRecommendation[], required — Entities whose row-level security should change, one entry per entity.
      - `entity_name` string, required — Entity the recommendation is for, as returned by [List entity schemas](/api-reference/list-entity-schemas).
      - `description` string, required — Why the scan recommends these rules, in plain language.
      - `create_rule` union, required — Recommended rule for creating a record. The rule to apply to this operation. `true` allows it for everyone, `false` blocks it outright, `null` leaves it unset, and an object is a filter matched against the record and the signed-in app user. Send the four rules to [Update entity schema](/api-reference/update-entity-schema) under the entity's `rls` to apply them.
        - object
        - boolean
      - `read_rule` union, required — Recommended rule for reading records. The rule to apply to this operation. `true` allows it for everyone, `false` blocks it outright, `null` leaves it unset, and an object is a filter matched against the record and the signed-in app user. Send the four rules to [Update entity schema](/api-reference/update-entity-schema) under the entity's `rls` to apply them.
        - object
        - boolean
      - `update_rule` union, required — Recommended rule for updating a record. The rule to apply to this operation. `true` allows it for everyone, `false` blocks it outright, `null` leaves it unset, and an object is a filter matched against the record and the signed-in app user. Send the four rules to [Update entity schema](/api-reference/update-entity-schema) under the entity's `rls` to apply them.
        - object
        - boolean
      - `delete_rule` union, required — Recommended rule for deleting a record. The rule to apply to this operation. `true` allows it for everyone, `false` blocks it outright, `null` leaves it unset, and an object is a filter matched against the record and the signed-in app user. Send the four rules to [Update entity schema](/api-reference/update-entity-schema) under the entity's `rls` to apply them.
        - object
        - boolean
    - `hardcoded_secrets` SecurityHardcodedSecret[], required — Credentials written into the app's code.
      - `file_path` string, required — Path of the file in the app where it was found.
      - `description` string, required — What was found and why it is a problem. The secret's own value is not included.
    - `backend_functions` SecurityBackendFunctionIssue[], required — Problems found in the app's backend functions.
      - `file_path` string, required — Path of the file in the app where it was found.
      - `description` string, required — What is wrong with the function and what to change.
    - `dependency_vulnerabilities` SecurityDependencyVulnerability[], required — Known vulnerabilities in the app's npm dependencies. Always empty for a caller outside the dependency-scanning rollout.
      - `package_name` string, required — Name of the npm package.
      - `current_version` string, required — Version the app currently has.
      - `vulnerable_range` string, nullable, required — Range of versions the advisory covers, or `null` when the advisory does not give one.
      - `fixed_version` string, nullable, required — First version the advisory says is fixed, or `null` when there is no fixed release.
      - `safe_fixed_version` string, nullable — The version Base44 checked is safe to install, which can be newer than `fixed_version`. It is `null` when no safe version was found, and absent on a finding recorded before Base44 started checking.
      - `fix_unavailable_reason` string, nullable — Why no safe upgrade exists, when that is the case. It is `null` or absent when there is one.
      - `vuln_id` string, required — Advisory identifier.
      - `severity` string, required — How serious it is, one of `critical`, `high`, `medium` or `low`.
      - `summary` string, required — One-line summary of the vulnerability.
      - `advisory_url` string, required — Link to the full advisory.
    - `static_code_findings` SecurityStaticCodeFinding[], required — Problems found by reading the app's code, listing only the findings that survived the scan's own second-pass check. It is an empty list when code-reading analysis is switched off for the app, which is not the same as a clean result, so read `static_code_enabled` before concluding there is nothing to find.
      - `title` string, required — Short name for the problem.
      - `severity` string, required — How serious it is, one of `critical`, `high`, `medium` or `low`.
      - `confidence` string, required — How sure the scan is, one of `high`, `medium` or `low`. A `low` confidence finding is worth reading before acting on.
      - `category` string, required — What kind of problem it is, one of `unauthorized_access`, `unsafe_user_input`, `exposed_sensitive_data`, `unsafe_redirect_or_external_request`, `unsafe_browser_code`, `payment_or_webhook_risk`, `file_handling_risk` or `other`.
      - `file_path` string, required — Path of the file in the app where it was found.
      - `line_number` integer, nullable, required — Line the finding points at, or `null` when the scan could not place it on one.
      - `evidence` string, required — The snippet of the app's own code the finding is about.
      - `attack_scenario` string, required — How someone would exploit it.
      - `impact` string, required — What it costs if exploited.
      - `recommendation` string, required — What to change.
      - `standards` SecurityStaticCodeStandard[], nullable — Security standards the finding maps to. Absent on a finding the scan did not classify.
        - `framework` string, required — Which catalog the identifier belongs to.
        - `id` string, required — Identifier within that catalog.
        - `name` string, required — Name of the entry.
    - `header_recommendations` SecurityHeaderRecommendation[], required — Recommended changes to the published app's HTTP headers. These are computed from the app's current settings on every read rather than stored with the scan.
      - `flag` string, required — Which setting to turn on, either `prevent_iframe_embedding` or `restrict_browser_features`.
      - `severity` string, required — How serious it is, one of `high`, `medium` or `low`.
      - `reason_key` string, required — Stable identifier for the reason. The readable text is Base44's own translated copy, so treat this as a code to branch on rather than something to show.
    - `core_integration_recommendation` string, nullable, required — Whether the app is ready for Base44's core-integration protection. `no_restricted_usage` means nothing in the app needs it, `compatible` means turning it on is safe, `would_be_blocked` means it would break the app as written, and `publish_required` means the app has to be published before this can be judged. It is `null` when the answer does not apply to this app.
    - `scanned_at` string, date-time, nullable, required — When the scan that produced these findings ran, or `null` on a result recorded before Base44 stored the time.
  - `static_code_enabled` boolean, required — Whether code-reading analysis is switched on for this app (`true`) or not (`false`). When it is `false`, `result.static_code_findings` comes back as an empty list, so this field is the only way to tell an analysis that found nothing from one that never ran.

## Other responses

- `401` — Missing or invalid credentials.
- `403` — You don't have access to this app.
- `404` — App not found.
- `422` — Validation Error
- `429` — Rate limit exceeded (5 requests per minute).

## Changes

- **2026-09-02** `56dc45634956` — 1 info
  - endpoint added

[Change history](https://skmtc.dev/idealspot/apis/base44-app-management-api/changes/api/apps/:app_id/security/scan/post.md)

---

[API](https://skmtc.dev/idealspot/apis/base44-app-management-api.md) · [All operations](https://skmtc.dev/idealspot/apis/base44-app-management-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/idealspot/base44-app-management-api/revisions/56dc45634956/schema)
