Managed rule feed
Deliver your organization's rules over HTTPS: the feed format, the fetch schedule, pinning and what happens when a fetch fails.
A managed rule feed is an HTTPS document holding rules your organization wants on every managed Mac. You force the address with the RuleFeedURL managed preference (optionally RuleFeedPinnedSHA256, see Managed preferences), and Outbound downloads the feed, installs its rules, and keeps them current. Rules from the feed are called managed rules; on this Mac they are marked as the organization’s and cannot be edited or deleted one by one.
Feed format
Section titled “Feed format”The feed is the same envelope as the app’s own rules file:
{ "schemaVersion": 1, "rules": [ { "id": "8E2A6B40-3C1D-4F57-9A0E-5B7C1D2E3F41", "action": "deny", "direction": "outgoing", "process": { "any": {} }, "remote": { "domain": { "_0": "telemetry.example.net" } }, "ports": { "any": {} }, "proto": "any", "lifetime": { "forever": {} }, "priority": false, "enabled": true, "source": { "managed": {} }, "createdAt": "2026-10-01T09:00:00Z", "note": "Block vendor telemetry" } ]}The full field reference is in The rules file format. What matters for a feed:
schemaVersion1 and 2 are accepted. A schema above what this build understands is refused with a message naming the version.- Every rule needs a unique
id(a UUID). A repeated id makes the whole feed invalid: rules are addressed by id, so a duplicate is a real error, not a harmless extra. Keep the id of a rule stable between versions of your feed so any state tracking it follows. createdAtand the date inside anuntillifetime are ISO-8601 strings (fractional seconds allowed) or numbers counting seconds since 2001-01-01.- Only rules that Outbound can actually match are accepted. A match the filter would compile to nothing (a malformed host, domain, address, network, port range or process identity) invalidates the feed, and the message names the rule’s index, id and field.
- Lifetimes bound to a session or a process (
untilQuit,untilLogout,untilRestart) make the whole feed invalid; they mean nothing on another Mac. Useforeveroruntila date. An already expireduntilrule is kept and simply never matches. - A
profileIDnaming a profile this Mac does not have is not an error: the rule applies to no profile until a profile with that id exists. LeaveprofileIDout for a rule that must always apply. sourceis replaced withmanagedon install, whatever the file says, so a feed cannot plant rules that look like the user’s own.- At most 50,000 rules. A larger feed is refused whole.
Fetching
Section titled “Fetching”Outbound fetches the feed when the app launches and every 6 hours afterwards. After a failed fetch it tries again after 15 minutes instead of waiting for the next slot.
- The address must be HTTPS; anything else is reported as a configuration problem.
- The request is capped at 32 MiB. A larger response is refused unread.
- If the server sends an
ETag, the next fetch sendsIf-None-Match, and a 304 answer costs no download and no rewrite. Redirects must stay on HTTPS and on the feed’s own host, unless the new host is listed inRuleFeedAllowedRedirectHosts. - Validation happens on every fetch: the envelope, the rule count, duplicate ids and every rule. A feed that fails any check leaves the previously installed managed rules in force, and Settings shows the error.
Pinning
Section titled “Pinning”RuleFeedPinnedSHA256 is the SHA-256 of the exact feed bytes. When it is forced, the downloaded bytes are hashed and compared against the pin (case-insensitive); a mismatch refuses the feed with both digests in the message. Compute the pin yourself:
shasum -a 256 rule-feed.jsonoutboundctl feed check rule-feed.json --pin <sha256>A forced pin that is malformed (empty, whitespace, wrong length, not hexadecimal) is treated as an error, never as “no pin”: a half-cleared pin must not silently turn verification off.
Outbound 1.2 can also require signed feeds: force RuleFeedPublicKeys with base64 Ed25519 public keys, and every feed must be signed by one of them. DeviceGroups matches a feed’s targets, and RuleFeedAllowRollback allows outboundctl feed rollback. See Managed preferences.
Signing your feed
Section titled “Signing your feed”A pin proves the bytes are the ones you expect, but you must update it with every feed. A signature proves who wrote the feed, so one key covers every version you publish.
- Create a key pair once, on a Mac you trust:
outboundctl feed keygen --out feed-signing.key. Keep the private key file private. Put the printed public key inRuleFeedPublicKeys. - Add an envelope to the feed’s JSON, next to
schemaVersionandrules:feedVersion, a whole number you raise with every release, andissuedAtandnotAfter, RFC 3339 dates. You can addtargets, a list of group names; a Mac then installs the feed only when one of them is in itsDeviceGroups. - Sign it:
outboundctl feed sign --key feed-signing.key rule-feed.jsonwritesrule-feed.json.sig. - Check it:
outboundctl feed verify rule-feed.json --pubkey <base64>. - Publish the feed and its
.sigfile side by side. Outbound downloads the signature from the feed’s address with.sigadded.
A Mac refuses a signed feed whose version is lower than one it has already accepted, or whose notAfter has passed (with five minutes allowed for clock differences), so an old genuine feed can’t be replayed. To move to a new key, list both public keys in RuleFeedPublicKeys until every Mac has the new feed. outboundctl feed status shows what a Mac installed, and outboundctl feed rollback reinstalls a kept version when the profile forces RuleFeedAllowRollback. See outboundctl feed.
How rules are installed
Section titled “How rules are installed”The managed rules in the rule store are replaced by the feed’s rules as a set, in one write. Your own rules, blocklist rules and rule-group rules are untouched, in their original order, with the feed’s rules appended. An empty rules array removes all managed rules.
Only the managed rules the app itself fetched and verified skip the approval that otherwise guards rule changes; the presence of managed rules in the file alone proves nothing.
Changing and removing the feed
Section titled “Changing and removing the feed”- Changing
RuleFeedURLor the pin starts over with an immediate fetch. A download of the old address can never install after that, even if it was already in flight. - Removing
RuleFeedURLfrom the profile removes the managed rules from the Mac, in one transaction; a fetch that was running is cancelled and its result discarded. If the app is not running, the removal happens at its next launch. - A feed that is forced but unusable (the address is not HTTPS, the pin is mistyped) keeps the rules it already installed and shows the problem in Settings. The administrator still means to have a feed, so the rules stay until a valid fetch replaces them.
Where the rules appear
Section titled “Where the rules appear”Managed rules show in the Rules pane with the source “Organization”, and their detail lines say “set by your organization”. They cannot be removed one by one: outboundctl rules remove <uuid> exits 77 for a managed rule, even when run as root. To change what the fleet blocks, publish a new feed.
Status in Settings
Section titled “Status in Settings”When a feed is forced, Settings › General shows an Organization section:
- “Organization rules: last updated
, rules” after a successful fetch. - “Organization rules: updating…” while a fetch runs.
- “Organization rules: not updated yet” until the first fetch completes.
- The error from the last failed fetch, below the summary line.
Checking a feed before publishing
Section titled “Checking a feed before publishing”outboundctl feed check rule-feed.jsonoutboundctl feed check https://example.com/rule-feed.json --pin <sha256>feed check validates a file or an HTTPS address exactly as the app does and prints the rule count. Exit status 0 when the feed is valid, 65 when it is not, 1 when it cannot be read or downloaded. Warnings (today: a profile this Mac does not have) are printed to stderr and do not make the feed invalid.