# Federated Threat Intelligence: Sharing IOCs Without Sharing Content

> Source: <https://dev.to/aegisgate/federated-threat-intelligence-sharing-iocs-without-sharing-content-bpk>
> Published: 2026-10-06 23:37:15+00:00

The fundamental problem in threat intelligence is latency. Organization A detects a novel prompt injection. Organizations B, C, and D won't see it until someone writes a blog post, a vendor updates a signature, and a SIEM rule gets deployed. In AI security, that latency window is measured in hours — and attacks iterate faster than that.

I've been building [AegisGate](https://github.com/aegisgatesecurity) — an open-source AI security platform — and we just shipped a federated threat intelligence system that closes that gap. This post is about the architecture and the hard design decisions.

AI attacks are distributed. An attacker hits Organization A with a novel prompt injection today, and hits Organizations B through Z tomorrow. Traditional threat intel sharing has too much friction:

We needed something where the *first* organization to see an attack instantly benefits every other organization — without sharing content, without a central authority, and without blind trust.

When AegisGate detects a threat, it creates an Indicator of Compromise (IOC). But we don't share the raw attack payload. We compute a SHA-256 fingerprint over the canonicalized detection struct — capturing the technique, pattern match, and confidence without any original content.

Two organizations can independently detect the same novel attack, produce the same fingerprint, and confirm they're seeing the same thing — without either knowing what the other's actual prompt said.

Instances communicate via HTTP gossip. Every instance exposes a `/manifest` endpoint listing its signed IOC bundles. Peers periodically pull manifests, verify signatures, and ingest new IOCs.

Each bundle is signed with **ECDSA P-256**. The keyring is per-instance, and peers discover each other's public keys through a bootstrap peer list. No central authority — it's a trust mesh.

```
type Bundle struct {
    IOCs      []IOC        `json:"iocs"`
    Signature ECDSASig     `json:"signature"`
    PublicKey ECDSAPubKey  `json:"publicKey"`
    Timestamp time.Time    `json:"timestamp"`
}
```

Not all peers are equal. We track reputation using an **Exponentially Weighted Moving Average (EWMA)** with a 7-day half-life:

Scores range 0.0 to 1.0. The threshold for "trusted" is configurable, and reputation determines how IOCs from that peer are handled.

This is the core insight. When your local AegisGate detects a threat, it creates a local IOC. If a peer later shares an IOC with the same fingerprint, that's **corroboration** — independent confirmation.

In **conservative mode** (default), corroboration escalates the response: "alert and log" becomes "block." One organization's threat → every organization's protection.

In **aggressive mode**, peer IOCs alone can trigger blocking — for high-trust federation partners where you want to benefit from their detections before you see the attack yourself.

Beyond peer gossip, we support standard TAXII feeds for existing TI platforms. Each feed has a configurable reputation weight (0.0–1.0) and severity floor. High-trust feeds (≥0.5) count as corroboration; low-trust feeds contribute IOCs but don't independently escalate.

Shipping the gossip protocol was necessary but not sufficient. Four hardening layers were needed for production.

Every gossip endpoint is rate-limited per-IP with a token bucket (default 60/min). A CIDR allow-list lets trusted partner networks bypass:

```
type SyncConfig struct {
    RateLimitPerMinute int      // default 60
    PeerAllowList      []string // CIDRs that bypass rate limiting
}
```

This prevents a compromised peer from DOSing your manifest endpoint and caps the blast radius of a flooding peer.

The IOC admin API already sits behind dashboard auth middleware. We added a second layer — bearer token authentication using `crypto/subtle.ConstantTimeCompare`:

```
func (a *iocAdminAPI) requireAdminToken(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        if a.adminToken == "" {
            next.ServeHTTP(w, r) // backward compatible: no token = no extra auth
            return
        }
        token := strings.TrimPrefix(r.Header.Get("Authorization"), "Bearer ")
        if subtle.ConstantTimeCompare([]byte(token), []byte(a.adminToken)) != 1 {
            w.Header().Set("WWW-Authenticate", "Bearer")
            http.Error(w, "Unauthorized", http.StatusUnauthorized)
            return
        }
        next.ServeHTTP(w, r)
    })
}
```

When the token is set, both layers must pass. When unset, backward compatible.

The ECDSA keyring file contains private keys that sign IOC bundles. In production, this can't sit on disk in plaintext.

We encrypt with **AES-256-GCM**. Passphrase → SHA-256 → 32-byte key. The encrypted file is a JSON envelope:

```
{
  "encrypted": true,
  "nonce": "<base64>",
  "ciphertext": "<base64>"
}
```

The system **auto-detects** whether the file is encrypted or plaintext on load. If encrypted and no passphrase → startup fails with a clear error. If passphrase is set and file is plaintext → automatically migrated to encrypted on the next key rotation. You deploy the env var, the migration happens transparently.

``` js
func isEncryptedKeyFile(data []byte) bool {
    var probe encryptedKeyFile
    if err := json.Unmarshal(data, &probe); err != nil {
        return false
    }
    return probe.Encrypted
}
```

Previously, IOCs from below-threshold peers were **rejected outright**. Safe, but wasteful — a below-threshold peer might be sharing legitimate IOCs you'd want once they earn your trust.

Instead of rejecting, we **quarantine**:

```
type IOC struct {
    Fingerprint  string    `json:"fingerprint"`
    Source       string    `json:"source"`
    Quarantined  bool      `json:"quarantined,omitempty"`
    // ...
}
```

IOCs from below-threshold peers are stored with `Quarantined = true`. The corroboration checker excludes them from blocking recommendations — they're invisible to enforcement. But they're sitting in the store, waiting.

When the peer's reputation crosses the threshold (or an admin manually promotes them), quarantined IOCs are un-quarantined and immediately available. No re-fetch needed.

**The critical guarantee:** trusted IOCs are never downgraded by quarantined merges. If a low-reputation peer shares an IOC matching one you already trust, the trusted IOC stays trusted. A compromised peer cannot taint your trust store:

```
func (s *Store) mergeQuarantinedIOC(incoming IOC) {
    s.mu.Lock()
    defer s.mu.Unlock()
    if existing, ok := s.iocs[incoming.Fingerprint]; ok {
        if !existing.Quarantined {
            // Already trusted — do NOT downgrade
            return
        }
    }
    incoming.Quarantined = true
    s.iocs[incoming.Fingerprint] = incoming
}
```

This pattern — store but don't act, promote later, never downgrade — turned out to be more useful than I expected. It's the same concept as a sandbox for suspicious files: you don't delete them, you don't execute them, you hold them for analysis.

We instrumented the pipeline with Prometheus metrics:

| Metric | What It Tracks | 
|---|---|
| `aegisgate_ioc_store_size` | Current IOC count | 
| `aegisgate_ioc_store_capacity` | Max IOCs before eviction | 
| `aegisgate_ioc_peer_count` | Total known peers | 
| `aegisgate_ioc_peer_reachable` | Currently reachable peers | 
| `aegisgate_ioc_feed_errors_total` | Per-feed error count | 
| `aegisgate_ioc_feed_iocs_total` | Per-feed IOC ingestion count | 
| `aegisgate_ioc_feed_last_pull_timestamp` | Last successful pull per feed | 

Plus a 13-panel Grafana dashboard and 10 Prometheus alert rules covering the failure modes (peer unreachable, feed errors, store capacity, quarantine buildup).

37 new tests across three tiers:

All 362 `pkg/ioc` tests pass. Full suite: 11,573+ tests across 127 packages.

For a single organization: your AegisGate deployment gets smarter over time. Every detection you make, every peer IOC you corroborate, sharpens your defenses.

For a federation (MSSPs, industry ISACs, enterprise partners): **collective defense**. The first organization to see a new attack pattern instantly protects every other organization in the mesh. No content shared. No privacy compromised. No central authority required.

The code is [open source](https://github.com/aegisgatesecurity/aegisgate-platform) (Apache 2.0). The IOC library is in `pkg/ioc/`. The full [release notes are here](https://github.com/aegisgatesecurity/aegisgate-platform/releases/tag/v4.5.2).

**Secure Every AI Interaction.**

*Josh Colvin is the founder of [AegisGate Security](https://aegisgatesecurity.io), building open-source, self-hosted AI security. Apache 2.0. No telemetry. No data egress. [GitHub](https://github.com/aegisgatesecurity/aegisgate-platform).*

*This post was originally published on the [AegisGate Security blog](https://aegisgatesecurity.io/blog/federated-threat-intelligence-sharing). AegisGate is an open-source AI security platform — browser extension, local proxy, and enterprise gateway. Apache 2.0, self-hosted, air-gapped capable.*
