## Upload scan settings (`upload-scan-settings`)

Platform-wide upload scanning (files in multipart form uploads only): master switch, dangerous extensions, double extensions, disguised files, webshell signatures, antivirus, per-file limit, scan timeout, action and exceptions; admin only. Webshell signatures, antivirus and the sha256 blocklist belong to the paid feature WAF enhanced.

Authentication: Admin only · Docs: https://www-demo.kuxitong.com/en/docs/api/upload-scan-settings

### GET `/api/v2/upload-scan-settings`

Get upload scan settings · Authentication: Admin only

```sh
curl "https://panel.example.com/api/v2/upload-scan-settings" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/upload-scan-settings`

Update upload scan settings · Authentication: Admin only

Request body:

| Field | Type | Required | Description |
|---|---|---|---|
| `action` | string |  | On a hit - block, log only, or observe for 3 days (log only, then block); dangerous files have no observation period. Values: ["block","log","observe"] |
| `disguise` | boolean |  | Disguised file detection (image extension but the magic bytes are a script or an executable). |
| `double_ext` | boolean |  | Double extension detection (e.g. a.php.jpg, a.asp;.jpg). |
| `enabled` | boolean |  | Master switch; false = no site is scanned. |
| `enhanced` | string |  | WAF enhanced state - full (active), readonly (expired but within the read-only buffer, License.readonly_days, 7 days by default; enhanced items still work but are read-only) or basic (not purchased or past the buffer; enhanced items are off, settings kept); ignored on update. Values: ["full","readonly","basic"] |
| `exceptions` | UploadScanException[] |  | Exceptions - skip the signature when the site and path prefix match (empty sig = the path is not scanned). Entries that tenants added by marking false positives (source=false_positive) must be sent back unchanged on replace, otherwise they are overwritten. |
| `expected_updated_at` | string |  | Optimistic lock - the updated_at as the caller read it (the version of the node.global config key, shared with CC and WAF settings; use 1970-01-01T00:00:00Z when the read value is null). If it differs from the stored one, 409 stale_version is returned and nothing is saved; omit to skip the check. |
| `exts` | string[] |  | Dangerous extensions (lowercase, without the dot); defaults to php phtml jsp jspx asp aspx ashx cer war sh cgi when omitted. A site may override with waf.upload_exts. |
| `max_file_mb` | integer |  | Per-file scan limit in MB (default 20); larger files only get the extension check and are handled per oversize. |
| `observe_until` | string |  | End of the observation period (set when action is observe); ignored on update, written by the server. |
| `on_parse_error` | string |  | On multipart parse errors (bad delimiter, oversized header, truncated body, too many parts) - block or allow (pass and log); default block. Values: ["allow","block"] |
| `on_timeout` | string |  | On scan timeout (or failure to read the body) - allow (pass and log) or block (default allow). Values: ["allow","block"] |
| `oversize` | string |  | Files over the limit - allow (pass and log) or block. Values: ["allow","block"] |
| `sha256` | object[] |  | Local sha256 blocklist (WAF enhanced). |
| `sig` | boolean |  | Webshell signatures (WAF enhanced). |
| `timeout_s` | integer |  | Scan timeout per request in seconds (default 2). |
| `updated_at` | string |  | Version in the response (updated_at of the node.global config key; null if never changed); ignored on update. |
| `virus` | string |  | Antivirus (ClamAV, WAF enhanced) - off, mem4g (nodes with at least 4 GB memory) or all nodes. Values: ["off","mem4g","all"] |

```sh
curl -X PUT "https://panel.example.com/api/v2/upload-scan-settings" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"action":"block","disguise":true,"double_ext":true,"enabled":true,"exceptions":[{"path":"/upload/avatar/","sig":"","site_id":0}],"exts":["php","jsp"],"max_file_mb":20,"on_parse_error":"block","on_timeout":"allow","oversize":"allow","sig":true,"timeout_s":2,"virus":"mem4g"}'
```

Upload scan settings object:

| Field | Type | Required | Description |
|---|---|---|---|
| `action` | string |  | On a hit - block, log only, or observe for 3 days (log only, then block); dangerous files have no observation period. Values: ["block","log","observe"] |
| `disguise` | boolean |  | Disguised file detection (image extension but the magic bytes are a script or an executable). |
| `double_ext` | boolean |  | Double extension detection (e.g. a.php.jpg, a.asp;.jpg). |
| `enabled` | boolean |  | Master switch; false = no site is scanned. |
| `enhanced` | string |  | WAF enhanced state - full (active), readonly (expired but within the read-only buffer, License.readonly_days, 7 days by default; enhanced items still work but are read-only) or basic (not purchased or past the buffer; enhanced items are off, settings kept); ignored on update. Values: ["full","readonly","basic"] (read-only) |
| `exceptions` | UploadScanException[] |  | Exceptions - skip the signature when the site and path prefix match (empty sig = the path is not scanned). Entries that tenants added by marking false positives (source=false_positive) must be sent back unchanged on replace, otherwise they are overwritten. |
| `expected_updated_at` | string |  | Optimistic lock - the updated_at as the caller read it (the version of the node.global config key, shared with CC and WAF settings; use 1970-01-01T00:00:00Z when the read value is null). If it differs from the stored one, 409 stale_version is returned and nothing is saved; omit to skip the check. |
| `exts` | string[] |  | Dangerous extensions (lowercase, without the dot); defaults to php phtml jsp jspx asp aspx ashx cer war sh cgi when omitted. A site may override with waf.upload_exts. |
| `max_file_mb` | integer |  | Per-file scan limit in MB (default 20); larger files only get the extension check and are handled per oversize. |
| `observe_until` | string |  | End of the observation period (set when action is observe); ignored on update, written by the server. (read-only) |
| `on_parse_error` | string |  | On multipart parse errors (bad delimiter, oversized header, truncated body, too many parts) - block or allow (pass and log); default block. Values: ["allow","block"] |
| `on_timeout` | string |  | On scan timeout (or failure to read the body) - allow (pass and log) or block (default allow). Values: ["allow","block"] |
| `oversize` | string |  | Files over the limit - allow (pass and log) or block. Values: ["allow","block"] |
| `sha256` | object[] |  | Local sha256 blocklist (WAF enhanced). |
| `sig` | boolean |  | Webshell signatures (WAF enhanced). |
| `timeout_s` | integer |  | Scan timeout per request in seconds (default 2). |
| `updated_at` | string |  | Version in the response (updated_at of the node.global config key; null if never changed); ignored on update. (read-only) |
| `virus` | string |  | Antivirus (ClamAV, WAF enhanced) - off, mem4g (nodes with at least 4 GB memory) or all nodes. Values: ["off","mem4g","all"] |
