Cairn

How this portal is secured

This is an inventory portal. It reads from the systems you connect, joins what each connection says about a machine into one record, and shows you the result; a machine two connections both describe is two rows. What follows is how that is built, including the parts that are weaker than the rest.

It only reads

Every connection is read-only against your systems. Nothing here writes to your directory, your device management, your network hardware or your asset register, and nothing changes a policy or a setting on your side. When a page offers to open one of your own consoles, it hands your browser a link and your existing session there does the rest.

That is a deliberate architectural limit rather than a habit. There is no proxying, no embedding and no brokering of sessions. The credentials you give this portal to read a console are held, encrypted as described below, and used only to read; none is ever handed to your browser or used to open a session for you. A link either carries the identifier it needs or it is not shown at all — you will see a missing button before you see one that lands nowhere.

Your data stays yours, and stays apart

Every list is narrowed three ways before it is drawn: to one organization, to the organizations your account belongs to, and to the connections that organization owns. A page may be asked for an organization in the address bar, and answers only when your account belongs to it. The identifiers that decide which of a vendor's customers a page is about are read from the organization's own record, never from the address bar, which is what keeps one customer's records out of another's page even when the two share a vendor account.

Assessments hold a copy of your directory structure — account names, group membership, organizational unit paths — and take the same separation as everything else. They are kept rather than overwritten, so a report can say what changed since the last one.

Credentials

  • The secrets you enter are encrypted before they are stored. If the encryption key is missing, saving is refused outright — nothing falls back to storing a secret in the clear.
  • The machine serving this portal deliberately cannot read the backup copy of that key. It was written once and the access was removed.
  • Sessions are stored as one-way hashes, so a copy of the database hands over no working sign-in.
  • A token used to file an assessment is issued for one organization, can do nothing but file one, is stored only as a hash, is shown once, and can be revoked. It reads nothing at all.
  • A staff account signing in with a password must give a second factor. A staff account signing in with Microsoft relies on its own tenant's sign-in policy, and this portal does not check that a second factor was used there.

Exports

Everything in an export came out of somebody's system, and a spreadsheet will run a field that begins with an equals sign. Exported values are made inert before they are written, because a device name is a place an instruction can hide and the person who opens the file is usually the one with the most access.

In the browser

No advertising, no analytics, no third-party scripts. One session cookie, and two that last minutes while a sign-in or a Microsoft connection is finished. Your light or dark choice, and whether you have seen the cookie notice, are kept in your browser's own storage rather than in a cookie. Script execution is locked to this application: the page will not run script from anywhere else, and it will not run inline script that is not one of a short list published with the page.

What is weaker, and why we are telling you

Styling is not locked down the way script execution is. The pages still carry many inline style attributes, and an attribute of that kind cannot be listed the way an inline script can — permitting them at all means permitting the category. Closing it properly means moving those styles into named classes, which is real work in progress rather than a switch. The practical difference: an attacker who could inject markup here could affect how a page looks and still could not run script.

There are no anti-forgery tokens. Two other things stand in their place: the session cookie is marked so browsers will not attach it to a form submitted from another site, and every state-changing request is checked against the address this portal is served on. A request that arrives with no origin at all is allowed through — that is a command-line client with no cookie to be confused into sending, not a page on another site, because a page cannot suppress those headers.

Repeated sign-in attempts are slowed on the machine serving the page. It is a speed bump held in memory, not a guarantee, and it is worth knowing that rather than reading the word "protected" and assuming more.

What we ask for, and what we hold

A connection is only as read-only as the permissions behind it, so here is the whole list. This is assembled from the table the collectors are checked against, not written out beside it — a permission added to the portal appears here, and one removed disappears, without anybody remembering to edit this page.

  • Microsoft 365
    • Microsoft Graph — AuditLog.Read.All, Device.Read.All, DeviceManagementConfiguration.Read.All, DeviceManagementManagedDevices.Read.All, DeviceManagementServiceConfig.Read.All, Directory.Read.All, Group.Read.All, Organization.Read.All, Policy.Read.All, RoleManagement.Read.Directory
      Only where a connection has switched on security alerts: SecurityAlert.Read.All
      To read the Temporary Access Pass policy, and a connection without it is still healthy: Policy.Read.AuthenticationMethod
    • Defender for Endpoint — Machine.Read.All
      Only where a connection has switched on vulnerability findings: Vulnerability.Read.All
  • Google Workspace — its credential states scopes, and this list names none for it yet, so nothing is compared for it.
  • Cisco Meraki — a credential this portal cannot read a scope back from. What it may do is set where it was issued, there is nothing here to compare it against, and the limit is real rather than a gap in the checking.
  • Ubiquiti UniFi — a credential this portal cannot read a scope back from. What it may do is set where it was issued, there is nothing here to compare it against, and the limit is real rather than a gap in the checking.
  • Snipe-IT — a credential this portal cannot read a scope back from. What it may do is set where it was issued, there is nothing here to compare it against, and the limit is real rather than a gap in the checking.
  • PRTG Network Monitor — a credential this portal cannot read a scope back from. What it may do is set where it was issued, there is nothing here to compare it against, and the limit is real rather than a gap in the checking.
  • CrowdStrike Falcon — its credential states scopes, and this list names none for it yet, so nothing is compared for it.
  • On-premises collector — a credential this portal cannot read a scope back from. What it may do is set where it was issued, there is nothing here to compare it against, and the limit is real rather than a gap in the checking.
  • SentinelOne — a credential this portal cannot read a scope back from. What it may do is set where it was issued, there is nothing here to compare it against, and the limit is real rather than a gap in the checking.
  • Veeam — a credential this portal cannot read a scope back from. What it may do is set where it was issued, there is nothing here to compare it against, and the limit is real rather than a gap in the checking.
  • Tenable — a credential this portal cannot read a scope back from. What it may do is set where it was issued, there is nothing here to compare it against, and the limit is real rather than a gap in the checking.
  • Qualys — a credential this portal cannot read a scope back from. What it may do is set where it was issued, there is nothing here to compare it against, and the limit is real rather than a gap in the checking.
  • Rapid7 InsightVM — a credential this portal cannot read a scope back from. What it may do is set where it was issued, there is nothing here to compare it against, and the limit is real rather than a gap in the checking.
  • HPE Aruba Networking Central — a credential this portal cannot read a scope back from. What it may do is set where it was issued, there is nothing here to compare it against, and the limit is real rather than a gap in the checking.
  • Azure virtual machines — a credential this portal cannot read a scope back from. What it may do is set where it was issued, there is nothing here to compare it against, and the limit is real rather than a gap in the checking.
  • Okta — a credential this portal cannot read a scope back from. What it may do is set where it was issued, there is nothing here to compare it against, and the limit is real rather than a gap in the checking.
  • Duo — a credential this portal cannot read a scope back from. What it may do is set where it was issued, there is nothing here to compare it against, and the limit is real rather than a gap in the checking.
  • NinjaOne — a credential this portal cannot read a scope back from. What it may do is set where it was issued, there is nothing here to compare it against, and the limit is real rather than a gap in the checking.
  • Kaseya VSA 10 — a credential this portal cannot read a scope back from. What it may do is set where it was issued, there is nothing here to compare it against, and the limit is real rather than a gap in the checking.
  • AWS EC2 instances — a credential this portal cannot read a scope back from. What it may do is set where it was issued, there is nothing here to compare it against, and the limit is real rather than a gap in the checking.
  • Google Cloud VM instances — a credential this portal cannot read a scope back from. What it may do is set where it was issued, there is nothing here to compare it against, and the limit is real rather than a gap in the checking.
  • Commvault — a credential this portal cannot read a scope back from. What it may do is set where it was issued, there is nothing here to compare it against, and the limit is real rather than a gap in the checking.
  • ServiceNow — a credential this portal cannot read a scope back from. What it may do is set where it was issued, there is nothing here to compare it against, and the limit is real rather than a gap in the checking.
  • Palo Alto Networks — a credential this portal cannot read a scope back from. What it may do is set where it was issued, there is nothing here to compare it against, and the limit is real rather than a gap in the checking.
  • Sophos Central — a credential this portal cannot read a scope back from. What it may do is set where it was issued, there is nothing here to compare it against, and the limit is real rather than a gap in the checking.
  • Huntress — a credential this portal cannot read a scope back from. What it may do is set where it was issued, there is nothing here to compare it against, and the limit is real rather than a gap in the checking.
  • Jamf Pro — a credential this portal cannot read a scope back from. What it may do is set where it was issued, there is nothing here to compare it against, and the limit is real rather than a gap in the checking.
  • Bitdefender GravityZone — a credential this portal cannot read a scope back from. What it may do is set where it was issued, there is nothing here to compare it against, and the limit is real rather than a gap in the checking.
  • Acronis Cyber Protect — a credential this portal cannot read a scope back from. What it may do is set where it was issued, there is nothing here to compare it against, and the limit is real rather than a gap in the checking.
  • JumpCloud — a credential this portal cannot read a scope back from. What it may do is set where it was issued, there is nothing here to compare it against, and the limit is real rather than a gap in the checking.
  • Automox — a credential this portal cannot read a scope back from. What it may do is set where it was issued, there is nothing here to compare it against, and the limit is real rather than a gap in the checking.
  • ESET PROTECT — a credential this portal cannot read a scope back from. What it may do is set where it was issued, there is nothing here to compare it against, and the limit is real rather than a gap in the checking.
  • Cove Data Protection — a credential this portal cannot read a scope back from. What it may do is set where it was issued, there is nothing here to compare it against, and the limit is real rather than a gap in the checking.
  • Syncro — a credential this portal cannot read a scope back from. What it may do is set where it was issued, there is nothing here to compare it against, and the limit is real rather than a gap in the checking.
  • Juniper Mist — a credential this portal cannot read a scope back from. What it may do is set where it was issued, there is nothing here to compare it against, and the limit is real rather than a gap in the checking.
  • ThreatDown — a credential this portal cannot read a scope back from. What it may do is set where it was issued, there is nothing here to compare it against, and the limit is real rather than a gap in the checking.
  • ExtremeCloud IQ — a credential this portal cannot read a scope back from. What it may do is set where it was issued, there is nothing here to compare it against, and the limit is real rather than a gap in the checking.

Each of those is behind a request this portal actually makes. Where a registration is used only to sign people in, the correct application permission list is empty — that is asserted rather than left unsaid, because "none expected" and "nobody checked" look identical from the outside.

Where we hold more than that, removing it is ours to do. For a Microsoft connection, the portal compares the Microsoft Graph permissions it was granted against the list above every time it checks the connection; it does not yet compare Defender's, or any other connection's. A missing permission fails that check, because it breaks a collector and you are the only one who can restore it. A surplus does not fail it — nothing is broken and you could not act on it if it did, since the excess sits on a grant only we can narrow. That is why it is not on your dashboard as a fault. It is here because you granted the permission and the party holding more than it needs should not be the one deciding when you hear about that. It is a statement, not a request.

The comparison for your own connections is not printed on this page, and deliberately: this page is readable without signing in, and which permissions your tenant granted is your configuration rather than ours. Ask and we will show you the difference for your tenant, in writing.

Where a gap is recorded rather than hidden

Two habits sit behind everything above. A source that could not be read is reported as unknown and never as zero, so a permission problem on our side is never shown to you as a clean result. And a number that depends on an assumption carries the assumption wherever it is printed, including into the report that reaches your inbox.

If something on this page does not match what you observe, that is a fault worth reporting. Every claim here is meant to be checkable.