> For the complete documentation index, see [llms.txt](https://help.cloudstoragesec.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://help.cloudstoragesec.com/how-it-works/integrations/icap-service.md).

# ICAP Service

The CSS ICAP Service lets any application that speaks ICAP (Internet Content Adaptation Protocol, RFC 3507) scan files for malware inline — before they are stored or delivered. It is a standards-compliant ICAP server that you deploy into your own AWS account with a single CloudFormation template. Your ICAP client (a custom application, proxy such as Squid, or a network appliance) hands each file to the server, the server scans it against your existing [API Agent](/console-overview/configuration/api-agent-settings.md), and the verdict determines whether the file is allowed through or blocked.

Common use cases include scanning file uploads before your application accepts them, scanning downloads before they reach end users, and adding malware scanning to proxies and gateways that already support ICAP.

### How It Works

Your ICAP client sends each HTTP message (an upload via `REQMOD` or a download via `RESPMOD`) to the ICAP server. The server streams the file to your API Agent (the [Cloud Storage Security Scanning API](/how-it-works/scanning-api.md)) for scanning and answers with a standard ICAP verdict:

| Scan result                          | ICAP response                                                                                                              | What your application should do               |
| ------------------------------------ | -------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------- |
| **Clean** (client sent `Allow: 204`) | `204 No Content`                                                                                                           | Forward the original file                     |
| **Clean** (no `Allow: 204`)          | `200 OK` echoing the original message                                                                                      | Forward the original file                     |
| **Infected**                         | `200 OK` carrying an encapsulated **`HTTP 403 Forbidden`** with an XML error body (`<Error><Code>VirusDetected</Code>...`) | Block: deliver the 403 to the end client      |
| **Scanner unreachable / error**      | ICAP `500` (**fail closed** — a file is never passed through unscanned)                                                    | Treat as a failure; retry or surface an error |

The server supports the full RFC 3507 feature set your client may use: `OPTIONS` discovery, `REQMOD` and `RESPMOD`, Preview (advertised at 4096 bytes), `Allow: 204`, and persistent connections. Files are streamed to disk rather than memory, so multi-gigabyte objects are handled without special configuration.

### Architecture

Everything deploys inside your VPC: an ECS Fargate service running the ICAP server behind an **internal** Network Load Balancer, a Secrets Manager secret holding the scan-API credentials, and CloudWatch logging. Nothing is exposed outside your VPC.

<figure><img src="/files/UUR0kbqo8YJmpBupkioa" alt=""><figcaption></figcaption></figure>

### Prerequisites

Before deploying, make sure you have:

1. A **Cloud Storage Security Console** deployed and active in your environment.
2. An [API Agent](/console-overview/configuration/api-agent-settings.md) deployed, configured, and reachable — this is the backend the ICAP server sends files to for scanning. Note its **base URL** and confirm it is healthy.
3. A console user with [**API Access enabled**](/console-overview/access-management/user-mgmt.md#setup-for-api-scanning-access) — the ICAP server uses this username and password to authenticate to the Scanning API.
4. An AWS account and the **VPC where your ICAP client runs**, with **two or more subnets** for the load balancer and the Fargate task.
5. **Outbound HTTPS (443) connectivity** from those subnets to the API Agent. Public subnets work as-is; private subnets need a NAT gateway route. If your API Agent is deployed behind an internal load balancer (a different VPC or an internal endpoint), you are responsible for connectivity between the two — VPC peering, Transit Gateway, or a shared VPC.
6. **Pull access to the CSS ICAP server image.** [Contact Us](/contact-us.md) with the region(s) you will deploy in and your AWS Organization ID (grants every account in your org) or one or more AWS account IDs. There is no image URI to paste — the template already references the correct in-region image.

### Deploying the ICAP Server

The CloudFormation template is published at a stable public URL:

```
https://css-cft.s3.us-east-1.amazonaws.com/Icap/css-icap-server-1.0.0.yaml
```

To deploy from the AWS Console:

1. Go to **CloudFormation > Create stack > With new resources (standard)**, choose **Amazon S3 URL**, and paste the template URL above.
2. Name the stack (e.g. `css-icap-server`) and fill in the parameters (see the table below).
3. Acknowledge the IAM capabilities notice and click **Submit**. The stack reaches `CREATE_COMPLETE` in about 5 minutes.
4. Open the **Outputs** tab — `IcapEndpoint` is the address your ICAP client will target.

You can provide the scan-API credentials in either of two ways:

* **Secrets Manager (recommended):** create a secret containing `{"username":"...","password":"..."}` with the API Access user's credentials and pass its ARN in the `ScanApiSecretArn` parameter.
* **Stack parameters:** enter the username and password directly in the `ApiUser` and `ApiPass` fields. Both are masked, and the stack creates the Secrets Manager secret for you.

In both cases credentials are injected at task launch from Secrets Manager — they are never stored in the container image or the task definition.

#### Key Parameters

| Parameter                                   | Required        | Meaning                                                                                                                                                                                                                                                 |
| ------------------------------------------- | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `VpcId`, `SubnetIds`                        | Yes             | Where the server and internal load balancer live. Use the same VPC as your ICAP client.                                                                                                                                                                 |
| `ApiUrl`                                    | Yes             | The base URL of your API Agent.                                                                                                                                                                                                                         |
| `ScanApiSecretArn` or `ApiUser` + `ApiPass` | Yes             | Scan-API credentials (see the two options above).                                                                                                                                                                                                       |
| `AllowedClientCidr`                         | Optional        | Restricts which addresses may connect on port 1344. Defaults to `0.0.0.0/0`, which means anything that can route to the internal load balancer (your VPC and peered networks — never the internet). Tighten to your client subnets for least privilege. |
| `DesiredCount`                              | Default 1       | Number of server tasks; the load balancer spreads connections across them. Scale horizontally for throughput.                                                                                                                                           |
| `EphemeralStorageGiB`                       | Default 30      | Scratch disk. Set to at least **2× your largest file**.                                                                                                                                                                                                 |
| `AssignPublicIp`                            | Default ENABLED | `ENABLED` for public subnets; `DISABLED` for private subnets with a NAT route.                                                                                                                                                                          |
| `DebugLogging`                              | Default false   | Set `true` to log full ICAP request lines and headers (never file content) for troubleshooting.                                                                                                                                                         |

{% hint style="info" %}
To deploy in a different region, launch the same template there — the server image is pulled automatically from that region's ECR replica, so there is no cross-region data transfer.
{% endhint %}

### Pointing Your ICAP Client at the Server

The stack output `IcapEndpoint` is your target:

```
icap://<nlb-dns-name>:1344/avscan
```

Any service name is accepted; `avscan` is conventional. For best results your client should:

* Send `REQMOD` (or `RESPMOD`) with the encapsulated HTTP message
* Send `Allow: 204` (recommended — the cheaper clean-file path)
* Reuse connections (persistent connections are supported and recommended)
* Optionally use Preview — the server advertises `Preview: 4096` in its `OPTIONS` response

### Validating the Deployment

From any machine inside the VPC with an ICAP client installed (for example `c-icap-client`, available in the `c-icap` package on Ubuntu), run three checks:

**1. Handshake** — expect `ICAP/1.0 200 OK` with `Methods: REQMOD, RESPMOD`:

```bash
c-icap-client -i <nlb-dns> -p 1344 -s avscan
```

**2. Clean file** — expect "No modification needed (Allow 204 response)":

```bash
echo "clean test" > /tmp/clean.txt
c-icap-client -i <nlb-dns> -p 1344 -s avscan -f /tmp/clean.txt -req http://example.com/clean.txt
```

**3. EICAR test file** — the industry-standard, harmless antivirus test file; expect an HTTP **403** block page:

```bash
printf '%s%s' 'X5O!P%@AP[4\PZX54(P^)7CC)7}$' 'EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*' > /tmp/eicar.com
c-icap-client -i <nlb-dns> -p 1344 -s avscan -f /tmp/eicar.com -req http://example.com/eicar.com
```

All three passing means the full chain — client → ICAP server → API Agent → verdict — is working. CSS can also provide a .NET reference ICAP client with the same checks and script-friendly exit codes (0 = clean, 1 = blocked); [Contact Us](/contact-us.md) if you would like a copy.

### Sizing and Performance

Scanning is inline: total latency is the upload to the ICAP server plus the scan itself. As a rule of thumb, allow **about 2 minutes per GB** and set your client's ICAP timeout to roughly 3× the expected worst case (we recommend at least 30 minutes for multi-gigabyte objects).

| To increase              | Adjust                                                                    |
| ------------------------ | ------------------------------------------------------------------------- |
| Throughput               | `DesiredCount` — the server is stateless, so adding tasks scales linearly |
| Maximum file size        | `EphemeralStorageGiB` — at least 2× your largest file                     |
| Concurrent scan capacity | `TaskCpu` / `TaskMemory` — CPU matters most for many concurrent scans     |

{% hint style="warning" %}
Make sure the idle timeout on your API Agent's load balancer covers your worst-case scan duration — the AWS default of 60 seconds will cut off large-file scans.
{% endhint %}

### Operations

* **Logs:** the CloudWatch log group `/css-icap-server/icap` records one line per request with the verdict (`CLEAN` / `INFECTED` / scan-API errors).
* **Health:** every task runs a real health probe every 30 seconds (ICAP `OPTIONS` answered and API Agent reachable). Unhealthy tasks are replaced automatically.
* **Debug logging:** if a client integration misbehaves, redeploy with `DebugLogging=true`, reproduce the issue, and send CSS the logs. File content is never logged. Set it back to `false` when done.

### Troubleshooting

| Symptom                              | Likely cause / fix                                                                                                                                                                                      |
| ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Stack `CREATE_FAILED` on the service | The task can't pull the container image because the subnets have no egress. Add a NAT route, or use public subnets with `AssignPublicIp=ENABLED`.                                                       |
| Tasks cycle unhealthy                | The health probe is failing. Check the CloudWatch logs — "scan API unreachable" indicates an egress or DNS problem; verify the NAT route and `ApiUrl`.                                                  |
| Client receives ICAP `500`           | The API Agent is unreachable or the credentials were rejected (fail closed by design). Verify the username/password and `ApiUrl`.                                                                       |
| Client can't connect on port 1344    | `AllowedClientCidr` doesn't cover the client, or the client is in a different VPC (the load balancer is internal). If the tasks are healthy but the client can't connect, it is almost always the CIDR. |
| Large uploads stall or reset         | The client-side ICAP timeout is too low, or `EphemeralStorageGiB` is too small for the object.                                                                                                          |

### Security Posture

* The load balancer is **internal** — nothing is reachable from the internet.
* The container image contains **no credentials**; they are injected from Secrets Manager at task launch.
* The container runs as a **non-root** user.
* Verdicts are **fail closed**: if the file cannot be scanned, it is not passed through.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://help.cloudstoragesec.com/how-it-works/integrations/icap-service.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
