
Security News
US Government Forces Anthropic to Pull Claude Fable Days After Launch
Anthropic says the directive cited national security concerns over a narrow jailbreak, but offered no specific technical details.
openclaw-a2a-gateway
Advanced tools
OpenClaw plugin implementing the A2A (Agent-to-Agent) v0.3.0 protocol — bio-inspired routing, discovery, and resilience for multi-agent ecosystems
English | 简体中文 | 繁體中文 | 日本語 | 한국어 | Français | Español | Deutsch | Italiano | Русский | Português (Brasil)
A production-ready OpenClaw plugin that implements the A2A (Agent-to-Agent) v0.3.0 protocol, enabling OpenClaw agents to discover and communicate with each other across servers — with zero-config install and automatic peer discovery.
The only A2A gateway with adaptive, bio-inspired routing, discovery, and resilience — designed for multi-agent ecosystems at scale.
score = affinity^n / (Kd^n + affinity^n) (Hill, 1910)_a2a._tcp SRV + TXT recordsdelay = baseDelay × load / (Km + load) provides a soft pressure zone instead of sudden rejection┌──────────────────────┐ A2A/JSON-RPC ┌──────────────────────┐
│ OpenClaw Server A │ ◄──────────────────────────► │ OpenClaw Server B │
│ │ (Tailscale / LAN) │ │
│ Agent: AGI │ │ Agent: Coco │
│ A2A Port: 18800 │ │ A2A Port: 18800 │
│ Peer: Server-B │ │ Peer: Server-A │
└──────────────────────┘ └──────────────────────┘
The plugin ships with sensible defaults — you can install and load it without any manual configuration:
# Clone
mkdir -p ~/.openclaw/workspace/plugins
cd ~/.openclaw/workspace/plugins
git clone https://github.com/win4r/openclaw-a2a-gateway.git a2a-gateway
cd a2a-gateway
npm install --production
# Register & enable
openclaw plugins install ~/.openclaw/workspace/plugins/a2a-gateway
# Restart
openclaw gateway restart
# Verify
openclaw plugins list # should show a2a-gateway as loaded
curl -s http://localhost:18800/.well-known/agent-card.json | python3 -m json.tool
The plugin will start with the default Agent Card (name: "OpenClaw A2A Gateway", skills: [chat]). You can customize it later — see Configure the Agent Card below.
If you prefer manual control or need to keep existing plugins in your config:
# Into your workspace plugins directory
mkdir -p ~/.openclaw/workspace/plugins
cd ~/.openclaw/workspace/plugins
git clone https://github.com/win4r/openclaw-a2a-gateway.git a2a-gateway
cd a2a-gateway
npm install --production
# Add to allowed plugins list
openclaw config set plugins.allow '["telegram", "a2a-gateway"]'
# Tell OpenClaw where to find the plugin
openclaw config set plugins.load.paths '["<FULL_PATH_TO>/plugins/a2a-gateway"]'
# Enable the plugin
openclaw config set plugins.entries.a2a-gateway.enabled true
Note: Replace
<FULL_PATH_TO>with the actual absolute path, e.g.,/home/ubuntu/.openclaw/workspace/plugins/a2a-gateway. Keep any existing plugins in theplugins.allowarray.
Every A2A agent needs an Agent Card that describes itself. If you skip this step, the plugin uses these defaults:
| Field | Default |
|---|---|
agentCard.name | OpenClaw A2A Gateway |
agentCard.description | A2A bridge for OpenClaw agents |
agentCard.skills | [{"id":"chat","name":"chat","description":"Chat bridge"}] |
To customize:
openclaw config set plugins.entries.a2a-gateway.config.agentCard.name 'My Agent'
openclaw config set plugins.entries.a2a-gateway.config.agentCard.description 'My OpenClaw A2A Agent'
openclaw config set plugins.entries.a2a-gateway.config.agentCard.url 'http://<YOUR_IP>:18800/a2a/jsonrpc'
openclaw config set plugins.entries.a2a-gateway.config.agentCard.skills '[{"id":"chat","name":"chat","description":"Bridge chat/messages to OpenClaw agents"}]'
Important: Replace
<YOUR_IP>with the IP address reachable by your peers (Tailscale IP, LAN IP, or public IP).
openclaw config set plugins.entries.a2a-gateway.config.server.host '0.0.0.0'
openclaw config set plugins.entries.a2a-gateway.config.server.port 18800
Generate a token for inbound authentication:
TOKEN=$(openssl rand -hex 24)
echo "Your A2A token: $TOKEN"
openclaw config set plugins.entries.a2a-gateway.config.security.inboundAuth 'bearer'
openclaw config set plugins.entries.a2a-gateway.config.security.token "$TOKEN"
Save this token — peers will need it to authenticate with your agent.
openclaw config set plugins.entries.a2a-gateway.config.routing.defaultAgentId 'main'
openclaw gateway restart
# Check the Agent Card is accessible
curl -s http://localhost:18800/.well-known/agent-card.json | python3 -m json.tool
You should see your Agent Card with name, skills, and URL.
To communicate with another A2A agent, add it as a peer:
openclaw config set plugins.entries.a2a-gateway.config.peers '[
{
"name": "PeerName",
"agentCardUrl": "http://<PEER_IP>:18800/.well-known/agent-card.json",
"auth": {
"type": "bearer",
"token": "<PEER_TOKEN>"
}
}
]'
Then restart:
openclaw gateway restart
For two-way communication, both servers need to add each other as peers:
| Server A | Server B |
|---|---|
| Peer: Server-B (with B's token) | Peer: Server-A (with A's token) |
Each server generates its own security token and shares it with the other.
node <PLUGIN_PATH>/skill/scripts/a2a-send.mjs \
--peer-url http://<PEER_IP>:18800 \
--token <PEER_TOKEN> \
--message "Hello from Server A!"
The script uses @a2a-js/sdk ClientFactory to auto-discover the Agent Card and select the best transport.
For long prompts or multi-round discussions, avoid blocking a single request. Use non-blocking mode + polling:
node <PLUGIN_PATH>/skill/scripts/a2a-send.mjs \
--peer-url http://<PEER_IP>:18800 \
--token <PEER_TOKEN> \
--non-blocking \
--wait \
--timeout-ms 600000 \
--poll-ms 1000 \
--message "Discuss A2A advantages in 3 rounds and provide final conclusion"
This sends configuration.blocking=false and then polls tasks/get until the task reaches a terminal state.
Tip: the default --timeout-ms for the script is 10 minutes; override it for very long tasks.
By default, the peer routes inbound A2A messages to routing.defaultAgentId (often main).
To route a single request to a specific OpenClaw agentId on the peer, pass --agent-id:
node <PLUGIN_PATH>/skill/scripts/a2a-send.mjs \
--peer-url http://<PEER_IP>:18800 \
--token <PEER_TOKEN> \
--agent-id coder \
--message "Run a health check"
This is implemented as a non-standard message.agentId field understood by this plugin. It is most reliable over JSON-RPC/REST. gRPC transport may drop unknown Message fields.
Even if the plugin is installed and configured, an LLM agent will not reliably "infer" how to call A2A peers (peer URL, token, command to run). For dependable outbound A2A calls, you should add an A2A section to the agent's TOOLS.md.
Add this to your agent's TOOLS.md so it knows how to call peers (see skill/references/tools-md-template.md for the full template):
## A2A Gateway (Agent-to-Agent Communication)
You have an A2A Gateway plugin running on port 18800.
### Peers
| Peer | IP | Auth Token |
|------|-----|------------|
| PeerName | <PEER_IP> | <PEER_TOKEN> |
### How to send a message to a peer
Use the exec tool to run:
\```bash
node <PLUGIN_PATH>/skill/scripts/a2a-send.mjs \
--peer-url http://<PEER_IP>:18800 \
--token <PEER_TOKEN> \
--message "YOUR MESSAGE HERE"
# Optional (OpenClaw extension): route to a specific peer agentId
# --agent-id coder
\```
The script auto-discovers the Agent Card, handles auth, and prints the peer's response text.
Then users can say things like:
The plugin supports all three A2A Part types for inbound messages. Since the OpenClaw Gateway RPC only accepts plain text, each Part type is serialized into a human-readable format before dispatching to the agent.
| Part Type | Format Sent to Agent | Example |
|---|---|---|
TextPart | Raw text | Hello world |
FilePart (URI) | [Attached: report.pdf (application/pdf) → https://...] | URI-based file reference |
FilePart (base64) | [Attached: photo.png (image/png), inline 45KB] | Inline file with size hint |
DataPart | [Data (application/json): {"key":"value"}] | Structured JSON data (truncated at 2KB) |
For outbound responses, the plugin converts structured mediaUrl/mediaUrls fields from the agent payload into FilePart entries in the A2A response. Additionally, file URLs embedded in the agent's text response (markdown links like [report](https://…/report.pdf) and bare URLs like https://…/data.csv) are automatically extracted into FilePart entries when they end with a recognized file extension.
The plugin registers an a2a_send_file tool that agents can call to send files to peers:
| Parameter | Required | Description |
|---|---|---|
peer | Yes | Target peer name (must match a configured peer) |
uri | Yes | Public URL of the file to send |
name | No | Filename (e.g., report.pdf) |
mimeType | No | MIME type (auto-detected from extension if omitted) |
text | No | Optional text message alongside the file |
agentId | No | Route to a specific agentId on the peer (OpenClaw extension) |
Example agent interaction:
a2a_send_file with peer: "AWS-bot", uri: "https://...", name: "report.pdf"Tailscale creates a secure mesh network between your servers with zero firewall configuration.
# Install on both servers
curl -fsSL https://tailscale.com/install.sh | sh
# Authenticate (same account on both)
sudo tailscale up
# Check connectivity
tailscale status
# You'll see IPs like 100.x.x.x for each machine
# Verify
ping <OTHER_SERVER_TAILSCALE_IP>
Use the 100.x.x.x Tailscale IPs in your A2A configuration. Traffic is encrypted end-to-end.
If both servers are on the same local network, use their LAN IPs directly. Make sure port 18800 is accessible.
Use public IPs with bearer token authentication. Consider adding firewall rules to restrict access to known IPs.
# Generate Server A's token
A_TOKEN=$(openssl rand -hex 24)
echo "Server A token: $A_TOKEN"
# Configure A2A
openclaw config set plugins.entries.a2a-gateway.config.agentCard.name 'Server-A'
openclaw config set plugins.entries.a2a-gateway.config.agentCard.url 'http://100.10.10.1:18800/a2a/jsonrpc'
openclaw config set plugins.entries.a2a-gateway.config.agentCard.skills '[{"id":"chat","name":"chat","description":"Chat bridge"}]'
openclaw config set plugins.entries.a2a-gateway.config.server.host '0.0.0.0'
openclaw config set plugins.entries.a2a-gateway.config.server.port 18800
openclaw config set plugins.entries.a2a-gateway.config.security.inboundAuth 'bearer'
openclaw config set plugins.entries.a2a-gateway.config.security.token "$A_TOKEN"
openclaw config set plugins.entries.a2a-gateway.config.routing.defaultAgentId 'main'
# Add Server B as peer (use B's token)
openclaw config set plugins.entries.a2a-gateway.config.peers '[{"name":"Server-B","agentCardUrl":"http://100.10.10.2:18800/.well-known/agent-card.json","auth":{"type":"bearer","token":"<B_TOKEN>"}}]'
openclaw gateway restart
# Generate Server B's token
B_TOKEN=$(openssl rand -hex 24)
echo "Server B token: $B_TOKEN"
# Configure A2A
openclaw config set plugins.entries.a2a-gateway.config.agentCard.name 'Server-B'
openclaw config set plugins.entries.a2a-gateway.config.agentCard.url 'http://100.10.10.2:18800/a2a/jsonrpc'
openclaw config set plugins.entries.a2a-gateway.config.agentCard.skills '[{"id":"chat","name":"chat","description":"Chat bridge"}]'
openclaw config set plugins.entries.a2a-gateway.config.server.host '0.0.0.0'
openclaw config set plugins.entries.a2a-gateway.config.server.port 18800
openclaw config set plugins.entries.a2a-gateway.config.security.inboundAuth 'bearer'
openclaw config set plugins.entries.a2a-gateway.config.security.token "$B_TOKEN"
openclaw config set plugins.entries.a2a-gateway.config.routing.defaultAgentId 'main'
# Add Server A as peer (use A's token)
openclaw config set plugins.entries.a2a-gateway.config.peers '[{"name":"Server-A","agentCardUrl":"http://100.10.10.1:18800/.well-known/agent-card.json","auth":{"type":"bearer","token":"<A_TOKEN>"}}]'
openclaw gateway restart
# From Server A → test Server B's Agent Card
curl -s http://100.10.10.2:18800/.well-known/agent-card.json
# From Server B → test Server A's Agent Card
curl -s http://100.10.10.1:18800/.well-known/agent-card.json
# Send a message A → B (using SDK script)
node <PLUGIN_PATH>/skill/scripts/a2a-send.mjs \
--peer-url http://100.10.10.2:18800 \
--token <B_TOKEN> \
--message "Hello from Server A!"
| Path | Type | Default | Description |
|---|---|---|---|
agentCard.name | string | OpenClaw A2A Gateway | Display name for this agent |
agentCard.description | string | A2A bridge for OpenClaw agents | Human-readable description |
agentCard.url | string | auto | JSON-RPC endpoint URL |
agentCard.skills | array | [{chat}] | List of skills this agent offers |
server.host | string | 0.0.0.0 | Bind address |
server.port | number | 18800 | A2A HTTP port (gRPC on port+1) |
storage.tasksDir | string | ~/.openclaw/a2a-tasks | Durable on-disk task store path |
storage.taskTtlHours | number | 72 | Auto-cleanup expired tasks after N hours |
storage.cleanupIntervalMinutes | number | 60 | How often to scan for expired tasks |
| Path | Type | Default | Description |
|---|---|---|---|
peers | array | [] | List of peer agents |
peers[].name | string | required | Peer display name |
peers[].agentCardUrl | string | required | URL to peer's Agent Card |
peers[].auth.type | string | — | bearer or apiKey |
peers[].auth.token | string | — | Authentication token |
| Path | Type | Default | Description |
|---|---|---|---|
security.inboundAuth | string | none | none or bearer |
security.token | string | — | Single token for inbound auth |
security.tokens | array | [] | Multiple tokens for zero-downtime rotation |
security.allowedMimeTypes | array | [image/*, application/pdf, ...] | Allowed MIME patterns for file transfer |
security.maxFileSizeBytes | number | 52428800 | Max file size for URI-based files (50MB) |
security.maxInlineFileSizeBytes | number | 10485760 | Max inline base64 file size (10MB) |
security.fileUriAllowlist | array | [] | URI hostname allowlist (empty = allow all public) |
| Path | Type | Default | Description |
|---|---|---|---|
routing.defaultAgentId | string | default | Agent ID for inbound messages |
routing.rules | array | [] | Rule-based routing rules (see below) |
routing.rules[].name | string | required | Rule name |
routing.rules[].match.pattern | string | — | Regex to match message text (case-insensitive) |
routing.rules[].match.tags | array | — | Match if message has any of these tags |
routing.rules[].match.skills | array | — | Match if target peer has any of these skills |
routing.rules[].target.peer | string | required | Peer to route to |
routing.rules[].target.agentId | string | — | Override agentId on the peer |
routing.rules[].priority | number | 0 | Higher = checked first |
| Path | Type | Default | Description |
|---|---|---|---|
resilience.healthCheck.enabled | boolean | true | Enable periodic Agent Card probes |
resilience.healthCheck.intervalMs | number | 30000 | Probe interval (ms) |
resilience.healthCheck.timeoutMs | number | 5000 | Probe timeout (ms) |
resilience.retry.maxRetries | number | 3 | Max retries for failed outbound calls |
resilience.retry.baseDelayMs | number | 1000 | Base delay for exponential backoff |
resilience.retry.maxDelayMs | number | 10000 | Max delay cap |
resilience.circuitBreaker.failureThreshold | number | 5 | Failures before circuit opens |
resilience.circuitBreaker.resetTimeoutMs | number | 30000 | Cooldown before half-open probe |
| Path | Type | Default | Description |
|---|---|---|---|
discovery.enabled | boolean | false | Enable DNS-SD peer discovery |
discovery.serviceName | string | _a2a._tcp.local | DNS-SD service name to query |
discovery.refreshIntervalMs | number | 30000 | How often to re-query DNS (ms) |
discovery.mergeWithStatic | boolean | true | Merge discovered peers with static config |
advertise.enabled | boolean | false | Enable mDNS self-advertisement |
advertise.serviceName | string | _a2a._tcp.local | DNS-SD service type to advertise |
advertise.ttl | number | 120 | TTL in seconds for advertised records |
| Path | Type | Default | Description |
|---|---|---|---|
observability.structuredLogs | boolean | true | Emit JSON structured logs |
observability.exposeMetricsEndpoint | boolean | true | Expose telemetry snapshot over HTTP |
observability.metricsPath | string | /a2a/metrics | HTTP path for telemetry |
observability.metricsAuth | string | none | none or bearer for metrics endpoint |
observability.auditLogPath | string | ~/.openclaw/a2a-audit.jsonl | Path for JSONL audit log |
timeouts.agentResponseTimeoutMs | number | 300000 | Max wait for agent response (ms) |
limits.maxConcurrentTasks | number | 4 | Max active inbound agent runs |
limits.maxQueuedTasks | number | 100 | Max queued tasks before rejection |
| Endpoint | Method | Description |
|---|---|---|
/.well-known/agent-card.json | GET | Agent Card discovery (alias: /.well-known/agent.json) |
/a2a/jsonrpc | POST | A2A JSON-RPC transport |
/a2a/rest | POST | A2A REST transport |
<host>:<port+1> | gRPC | A2A gRPC transport |
/a2a/metrics | GET | Telemetry snapshot (optional bearer auth) |
/a2a/push/register | POST | Register push notification webhook |
/a2a/push/:taskId | DELETE | Unregister push notification |
A companion CLI for developing and debugging A2A connections. Included in the cli/ directory.
cd cli && npm install && npm link # or: npx tsx cli/bin/a2a.ts
| Command | Purpose |
|---|---|
a2a health <peer> | Check if a peer is online (fetches Agent Card) |
a2a health --all | Ping all configured peers at once |
a2a card <url> | Display a remote Agent Card |
a2a send <peer> "message" | Send a message and show the response |
a2a stream <peer> "message" | Stream a response via SSE in real-time |
a2a status <peer> <taskId> | Query task status (with --wait for polling) |
a2a discover | Scan the local network for A2A agents via mDNS |
a2a trace <peer> "message" | Request lifecycle waterfall (resolve → card → send) |
a2a bench <peer> | Load test with latency percentiles (P50/P90/P99) |
All commands support --json for pipe-friendly output. Peers can be aliases from ~/.openclaw/a2a-peers.json or direct URLs.
This means the A2A request was accepted by the gateway, but the underlying OpenClaw agent dispatch did not complete.
Common causes:
openclaw config get auth.profiles
Fix options:
--non-blocking --waitplugins.entries.a2a-gateway.config.timeouts.agentResponseTimeoutMs (default: 300000)The plugin isn't loaded. Check:
# Verify plugin is in allow list
openclaw config get plugins.allow
# Verify load path is correct
openclaw config get plugins.load.paths
# Check gateway logs
cat /tmp/openclaw/openclaw-$(date +%Y-%m-%d).log | grep a2a
# Check if the A2A server is listening
ss -tlnp | grep 18800
# If not, restart gateway
openclaw gateway restart
Make sure the token in your peer config matches the security.token on the target server exactly.
This repo includes a ready-to-use skill at skill/ that guides AI agents (OpenClaw, Codex CLI, Claude Code, etc.) through the full A2A setup process step by step — including installation, configuration, peer registration, TOOLS.md setup, and verification.
Manually configuring A2A involves many steps with specific field names, URL patterns, and token handling. The skill encodes all of this as a repeatable procedure, preventing common mistakes like:
agentCard.url (JSON-RPC endpoint) with peers[].agentCardUrl (Agent Card discovery)plugins.load.paths (must be absolute)For OpenClaw:
# Copy to your skills directory
cp -r <repo>/skill ~/.openclaw/workspace/skills/a2a-setup
# Or symlink
ln -s $(pwd)/skill ~/.openclaw/workspace/skills/a2a-setup
For Codex CLI:
# Copy to Codex skills directory
cp -r <repo>/skill ~/.codex/skills/a2a-setup
For Claude Code:
# Copy to your project or workspace
cp -r <repo>/skill ./skills/a2a-setup
skill/
├── SKILL.md # Step-by-step setup guide
├── scripts/
│ └── a2a-send.mjs # SDK-based message sender (official @a2a-js/sdk)
└── references/
└── tools-md-template.md # TOOLS.md template for agent A2A awareness
The skill provides two methods for agents to call peers:
@a2a-js/sdk ClientFactory with auto agent card discovery and transport selectionOnce installed, tell your agent:
The agent will follow the skill's procedure automatically.
As multi-agent ecosystems scale from 2 peers to 20 or 200, standard A2A gateways hit predictable walls: routing picks the wrong peer, circuit breakers cut traffic entirely, discovery polls waste bandwidth, and overload hits like a cliff. This gateway solves these with mechanisms borrowed from cell signaling biology — the same principles cells use to route signals, handle receptor overload, and discover neighbors in dense tissue.
| Biology | Mechanism | A2A Feature | Reference |
|---|---|---|---|
| Ligand-receptor binding | Hill equation sigmoid | Affinity-scored routing — multi-dimensional match scoring with configurable steepness (n) and threshold (Kd) | Hill (1910) J Physiol 40 |
| Receptor desensitization | Phosphorylation → internalization → recycling | Four-state circuit breaker — gradual degradation (DESENSITIZED) before full block (OPEN), with exponential recovery curve | Bhalla & Bhatt (2007) BMC Syst Biol 1:54 |
| cAMP degradation | Phosphodiesterase enzyme decay | Signal decay notifications — importance score decays exponentially; retry abandoned when below threshold | Alon (2007) Intro to Systems Biology Ch.4 |
| Quorum sensing | Autoinducer concentration threshold | Density-aware discovery — adaptive polling with hysteresis (explore ↔ stable mode) based on peer population | Tamsir et al. (2011) Nature 469:212 |
| Signal pathway selection | Pathway efficacy × transduction speed | Adaptive transport — per-transport scoring by success rate × latency factor; untested pathways get explore-first priority | Kholodenko (2006) Nat Rev Mol Cell Biol 7:165 |
| Enzyme saturation | Michaelis-Menten kinetics | Soft concurrency limiting — progressive delay baseDelay × load/(Km + load) before the hard queue wall | Michaelis & Menten (1913) Biochem Z 49:333 |
All bio-inspired features are optional and backward-compatible — without explicit configuration, the gateway behaves identically to standard implementations. Enable them when your deployment outgrows the defaults:
| Feature | Enable when... | Config key |
|---|---|---|
| Hill affinity routing | 5+ peers with overlapping skills | routing.affinity |
| Four-state circuit breaker | Peers have intermittent failures | resilience.circuitBreaker.softThreshold |
| Signal decay retry | Webhook endpoints are unreliable | Enabled by default |
| Quorum-sensing discovery | Dynamic peer networks with DNS-SD | discovery.quorum |
| Adaptive transport | Peers expose multiple transports | Automatic (learns from usage) |
| MM soft concurrency | High-throughput sub-second operations | limits.saturation |
Benchmark suite:
node --import tsx --test tests/benchmark.test.ts— runs 5-dimension before/after comparison across all bio-inspired features.
| Version | Highlights |
|---|---|
| v1.2.0 | Peer skills routing, mDNS self-advertisement (symmetric discovery) |
| v1.1.0 | URL extraction, transport fallback, push notifications, rule-based routing, DNS-SD discovery |
| v1.0.1 | Ed25519 device identity, metrics auth, CI |
| v1.0.0 | Production-ready: persistence, multi-round, file transfer, SSE, health checks, multi-token, audit |
| v0.1.0 | Initial A2A v0.3.0 implementation |
See CHANGELOG.md for full details and Releases for downloads.
MIT
FAQs
OpenClaw plugin implementing the A2A (Agent-to-Agent) v0.3.0 protocol — bio-inspired routing, discovery, and resilience for multi-agent ecosystems
The npm package openclaw-a2a-gateway receives a total of 43 weekly downloads. As such, openclaw-a2a-gateway popularity was classified as not popular.
We found that openclaw-a2a-gateway demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Anthropic says the directive cited national security concerns over a narrow jailbreak, but offered no specific technical details.

Security News
A network of 152 Chrome live wallpaper extensions hid ad tracking and made extension-driven traffic look like Google search clicks.

Company News
Socket’s first CISO brings deep experience securing high-growth SaaS companies as open source supply chain threats accelerate.