---
name: azion-scan-file-uploads-with-an-ai-inference-firewall-function
description: >-
  Create a function that sends an uploaded file to a model through AI Inference, and run it on a firewall so a malicious upload never reaches the origin.
---

# Scan file uploads with an AI Inference firewall function

You can scan an upload with a model and deny a malicious file, from Azion Console. The function runs on [Firewall](/en/documentation/platform/firewall/) and calls the model through [AI Inference](/en/documentation/platform/ai-inference/). For the design this page builds, refer to [Screen file uploads for malicious content](/en/documentation/use-cases/secure-applications-and-networks/screen-file-uploads-for-malicious-content/).

---

## Prerequisites

- An Azion account. To create one, refer to [How to create an account on Azion](/en/documentation/fundamentals/creating-account/).
- A firewall with the **Functions** module turned on. For what a function does on a firewall, refer to [Functions for Firewall](/en/documentation/platform/firewall/functions/).
- A domain associated to that firewall, so the upload traffic reaches it.
- The upload routes to protect, such as `/upload` or `/documents/upload`.

---

## Create the firewall function

A function runs on a firewall when it registers a `firewall` handler. This one reads the request body, sends it to the model, and applies the verdict in the same request. To create it:

1. **Open the Functions page**

   Access [Azion Console](https://console.azion.com/) > **Products Menu** > **Libraries** > **Functions**.

2. **Select + Function**

3. **Name the function**

   Enter a unique, descriptive name for the function.

4. **Paste the code in the Code tab**

   In the **Code** tab, paste the function below.

5. **Paste the arguments in the Arguments tab**

   In the **Arguments** tab, paste the JSON below.

6. **Select Save**

The **Code** tab takes this function:

```js
async function handleRequest(event) {
  try {
    const requestBody = await event.request.text();
    const { model, action, prompt } = event.args;
    const contentType = event.request.headers.get("content-type");

    // Allows images
    if (contentType && contentType.startsWith("image/")) {
      event.continue();
      return;
    }

    // Decodes the content if it's base64
    const decodedBody = contentType && contentType.includes("base64")
      ? atob(requestBody.split(",")[1])
      : requestBody;

    // Calls the model via Azion.AI.run
    const modelResponse = await Azion.AI.run(model, {
      stream: false,
      seed: 42,
      temperature: 0,
      max_tokens: 1024,
      messages: [
        {
          role: "system",
          content: `${prompt}`
        },
        {
          role: "user",
          content: decodedBody
        }
      ]
    });

    // Extracts the model's response
    const result = modelResponse?.choices?.[0]?.message?.content?.trim();

    if (result === "true") {
      event.console.warn(`[AI] ${result}`);
      event[action]();
      return;
    }
  } catch (err) {
    event.console.error("Error handling request:", err.message);
    event.continue();
    return;
  }

  event.continue(); // If not malicious, let it pass
}

addEventListener("firewall", event => {
  event.waitUntil(handleRequest(event));
});
```

The **Arguments** tab takes this JSON:

```json
{
  "model": "casperhansen-mistral-small-24b-instruct-2501-awq",
  "prompt": "You are a security assistant specialized in detecting malicious PDF files. Analyze the provided content carefully and return 'true' only if you identify malicious content, such as embedded scripts, suspicious patterns, or known vulnerabilities. Do not classify a file as malicious based solely on its structure or the presence of a PDF header. If the content is safe or does not contain clear malicious indicators, return 'false'. Do not provide any additional explanation or output.",
  "action": "deny"
}
```

The function is saved and available to instantiate on a firewall.

The function reads the request body and lets an image content type through untouched. It decodes base64 content, sends it to the model with the prompt from the arguments, and applies the action. The action, `deny` in this example, runs only when the model answers `true`. On any error, the function logs the message and lets the request continue.

The arguments select [Mistral 3 Small](/en/documentation/platform/ai-inference/mistral-3-small/), whose id is `casperhansen-mistral-small-24b-instruct-2501-awq`. Make sure the model you choose is available and configured in your account. For every id you can pass, refer to [AI models](/en/documentation/platform/ai-inference/models/).

The handler runs on [Functions](/en/documentation/platform/functions/). For every field `Azion.AI.run` accepts, refer to [Model invocation](/en/documentation/platform/ai-inference/model-invocation/). For what happens after the call, refer to [How AI Inference works](/en/documentation/platform/ai-inference/how-it-works/).

---

## Enable the firewall modules

The function runs on a firewall, and a firewall runs a function only when its **Functions** module is on. To prepare the firewall:

1. **Open the Firewall page**

   In Azion Console, go to **Products Menu** > **Firewall**.

2. **Select the firewall that secures the upload routes**

3. **Turn on the modules the design needs**

   In the **Main Settings** tab, turn on the **DDoS Protection**, **Functions**, **Network Shield**, and **Web Application Firewall** modules.

4. **Select Save**

The firewall now runs the modules this design depends on, and it can hold a function instance.

---

## Instantiate the function on the firewall

A function instance binds the function to one firewall. To create the instance:

1. **Go to the Functions Instances tab**
2. **Select + Function Instance**
3. **Enter a name for the instance**
4. **Select the function you created**
5. **Select Save**

The instance appears in the **Functions Instances** tab. It does not run until a Rules Engine rule selects it.

---

## Add the rule that runs the function

A Rules Engine rule sets the criteria that trigger the instance. To run it on the uploads your application receives:

1. **Go to the Rules Engine tab**

2. **Select + Rule**

3. **Enter a name for the rule**

4. **Select the Request URI variable**

   In the **Criteria** section, select the `Request URI` variable.

5. **Set the comparison operator to starts with**

6. **Enter the upload route**

   Enter an upload route as the argument, such as `/upload`.

7. **Select Run Function**

   In the **Behaviors** section, select **Run Function**.

8. **Select the instance you created**

9. **Select Save**

The rule runs the function on every request whose URI starts with that route. A file the model calls malicious is denied before the origin receives it. Changes can take a few minutes to propagate. Wait before you send an upload that matches the criteria.

---

## Monitor and tune the policy

A model decides what the policy blocks, so its record is the only way to check it. Watch these signals in [Real-Time Metrics](/en/documentation/platform/real-time-metrics/) and [Real-Time Events](/en/documentation/platform/real-time-events/):

- The rate of uploads blocked, allowed, and quarantined.
- Patterns by country, IP, ASN, route, and time.
- Events correlated with the security incidents your team reports.

Then tune the policy against what you read:

- The prompt in the **Arguments** tab, which sets how strictly the model answers.
- Whether a suspect upload is denied or held for review in [Object Storage](/en/documentation/platform/object-storage/).
- The Web Application Firewall and Network Shield rules on the same firewall.
- The volume the function sends to the model, within [AI Inference limits](/en/documentation/platform/ai-inference/limits/).
- The false positives and false negatives your analysts label, fed back into the prompt.

The signals show what the function decided, and each adjustment changes what the next reading shows.

---

## Next steps

- [Screen file uploads for malicious content](/en/documentation/use-cases/secure-applications-and-networks/screen-file-uploads-for-malicious-content.md): The design this page builds, with its dataflow and the components it puts in the request path.
- [AI Inference best practices](/en/documentation/platform/ai-inference/best-practices.md): The decisions the function takes before the call: the model id, the input it sends, and how it reads the response.
