---
module: aria.ioc-management
title: IOC Management
tab: Internal
order: 20
audience: internal
---

Ops/support/admin view of the ARIA IOC watchlist. The screen is a thin CRUD over the `threat_ioc` table in `hiveiq_aria`, served by `hiveops-aria` (port 8095) via `ThreatIocController` (`/api/aria/ioc`). Editing the watchlist directly changes what the threat-classification pipeline matches device events against.

## Who can use it

- **`BCOS_ADMIN` only.** Every list/create/update/deactivate endpoint is gated `@PreAuthorize("hasRole('BCOS_ADMIN')")`. This is **not** the usual `hasAnyRole('MSP_ADMIN','BCOS_ADMIN')` pattern — an MSP_ADMIN JWT will get **403** on this screen. If a customer/admin reports "IOC page is empty / won't load," check their role first.
- `GET /api/aria/ioc/active` is the one exception — no role gate, any authenticated caller can read active IOCs. It is used by internal consumers, not this UI.

## What the buttons actually do

| UI action | Endpoint | Effect |
|-----------|----------|--------|
| **+ Add IOC** | `POST /api/aria/ioc` | Inserts a row with `source = MANUAL` (always forced server-side, regardless of what you type). |
| **Edit → Update** | `PUT /api/aria/ioc/{id}` | Updates **value, description, confidence, expires_at only**. |
| **Deactivate** | `DELETE /api/aria/ioc/{id}` | **Soft** delete — sets `active = false`, returns 204. Row is never removed. |

- **Deactivate is not delete.** There is no hard-delete endpoint. Deactivated IOCs stay in the table and reappear under **Show inactive**. To "remove" a bad entry, deactivate it.
- IOC **Type cannot be changed** after creation — the form disables the select on edit, and the backend `update` ignores type. If the type is wrong, deactivate and re-add.

## First things to check when it misbehaves

1. **403 / blank list** → caller lacks `BCOS_ADMIN`. Decode the JWT `role` claim.
2. **"Save Failed" toast on add/edit** → validation: `iocType` (`@NotNull`) and `value` (`@NotBlank`) are required. The UI also blocks empty type/value client-side, so a server-side failure usually means a bad enum value for `iocType`/`confidence` or the service being down.
3. **Edited "Source Reference" didn't stick** → **known bug** (see below), not user error.
4. **New IOC not triggering detections** → confirm it is `active = true` and the `value` matches exactly (matching is case-insensitive but otherwise exact — see [architect]). Matching only happens for incoming events processed by `ThreatEventClassifier`; it is not retroactive to past events.
5. **Service reachability** → `curl http://localhost:8095/actuator/health` on the services VM; DB is on `10.10.10.188` (`hiveiq_aria`), not the services VM.

## Common failure modes + fixes

- **Duplicate-looking IOCs** — the CRUD endpoints do **not** de-duplicate. Only the external-feed importer (`IocFeedService`) checks for an existing active IOC of the same type+value. Two identical MANUAL entries are allowed; deactivate the extra.
- **Wrong confidence default** — if `confidence` is omitted on create the server defaults it to `MEDIUM`; the UI always sends `HIGH`. If IOCs show up as MEDIUM unexpectedly, something is calling the API directly without the field.
- **Feed-sourced IOCs you can't explain** — rows with `source` of `FBI_FLASH`, `FS_ISAC`, `OTX`, `MALWARE_BAZAAR`, or `THREAT_FOX` came from the seed migration or the scheduled feed refresh, not a person. Manage feed behavior on the **IOC Feeds** screen, not here.
- **Seed data** — `FILENAME` IOCs like the Ploutus jackpotting set were seeded by Flyway `V2` (`FLASH-20260219-001`). Deactivating them is safe and reversible.

## Known code bug (grounded, unfixed)

- `ThreatIocController.update()` sets value/description/confidence/expiresAt but **never reads `request.getSourceRef()`**. The Edit panel exposes a **Source Reference** field and the frontend sends it, but PUT silently ignores it. Editing Source Reference on an existing IOC is a no-op. Workaround: deactivate and re-create with the correct source reference. (Create honors `sourceRef`; update does not.)

## Related internal screens

- **IOC Feeds** — external feed status/refresh (`IocFeedService`, `ioc_feed_run` table).
- See [architect] for how the watchlist feeds the classification + precursor-sequence pipeline, and [claude] for the terse endpoint/table reference.
