Skip to content

Latest commit

 

History

4 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Specdeck

Everything this device can be asked about itself — and what it costs to ask.

iOS 26+ SwiftUI 70 identifiers Zero dependencies English, Russian, Turkish MIT license

Try the device report →

Specdeck's coverage ring showing how much of the device is readable, then scrolling through all eight categories

What it does

Your phone knows a lot of things about itself, and it hands them out on wildly different terms. Some are free to any app that asks. Some cost you a permission prompt. Some need an Apple entitlement and a server. Some Apple sealed off years ago and no app will ever read again. And a handful — your UDID, your serial number, your IMEI — only your device can disclose, about itself, to you.

Specdeck is a catalog of all 70 of them, sorted by what it costs to ask. Every entry says what the identifier is, who else can see it, what resets it, and why it matters. The ring on the front counts how many are readable right now, and deliberately leaves out the ones Apple has closed off — grading your phone down for a platform decision would make the number meaningless.

The gaps are the interesting part. A MAC address that's been frozen since iOS 7, a carrier name removed in iOS 16, an IDFA that reads all zeros until you allow tracking. Specdeck shows those rows rather than hiding them, because why you can't have a value tells you more than the value would have.

Tapping into the Identity category: values arrive masked, then reveal one by one, then all at once with an auto-relock warning

Masked until you ask. Sensitive values arrive redacted at the same length and grouping as the real thing, so you can see how much is being withheld without the layout jumping when you reveal it.

The Privacy tab: 'Specdeck reads. It does not send.', a network ledger reading zero requests, and the erase control

A counter, not a promise. Every outbound request is tallied on the Privacy tab. It starts at zero and stays there unless you switch something on. That's more convincing than a paragraph saying the same thing.

Why it's good

The erase button is a demonstration, not a setting. Wipe the identifiers Specdeck created about your install, then watch what comes back: the install ID is brand new, the keychain ID is byte-for-byte identical, and IDFV doesn't move at all. Three identifiers that look alike in a list behave completely differently when you attack them. That difference is the whole subject of the app.

Consent is enforced by the compiler. SpecdeckAPI cannot be constructed without a ConsentToken, and only ConsentStore can mint one — its initializer is fileprivate. "No network request without consent" is a property the type system checks, not a runtime if somebody eventually forgets to write.

Your UDID never touches a disk. The device signs its report with a certificate whose subject contains the UDID. The server verifies that chain in-process, holds the values in memory for minutes at most, and deletes them the moment the app has read them. The logger is an allowlist — it emits only fields whose names appear in LOGGABLE_FIELDS and silently drops everything else, so a device identifier reaching docker logs isn't a mistake someone can make.

It tells you what your device actually did. Specdeck requests MEID, ICCID, IMSI and EID on every report knowing most come back empty, then shows you exactly which ones your hardware withheld. That's a finding about your phone, not a fixed answer copied out of documentation.

The Catalog tab: a searchable flat list of every identifier in the registry The Device report category: UDID, serial number, IMEI, MEID and ICCID, each behind a 'Run device report' button

FAQ

Does Specdeck send my identifiers anywhere?

No, and there's a counter on the Privacy tab proving it. Everything in the deck is read on-device. Two features can reach the network — asking a server what it sees about you, and the device report — and both are off until you turn them on, each behind its own consent.

Then how does the device report get my UDID?

Your device tells you. Apple removed the ability for apps to read the UDID in 2013 and nothing has brought it back. The report uses Apple's own Over-the-Air Profile Delivery mechanism: your device signs a report about itself and posts it to the server, which hands it straight back to you and deletes it. No app read anything — the device disclosed it.

Does it install anything on my phone?

No. And this is the strange part: iOS will tell you "Profile installation failed", and that message is the successful ending. Apple's enrollment protocol assumes a server wants to install something, and gives you no way to say "we're done, install nothing". So iOS reports a failure at the end of an exchange that worked perfectly. Your identifiers arrived before that dialog appeared, and Settings → General → VPN & Device Management stays empty. The alternative was installing something you didn't ask for, which seemed worse than explaining a dialog.

What if someone's looking over my shoulder, or I'm recording my screen?

Sensitive values need a deliberate press and hold and re-hide themselves afterwards. Reveal-all exists for when you actually want to read a dozen of them, and re-masks automatically after 60 seconds — so walking away with the app open isn't a mistake you can make either. Serial numbers, IMEIs and UDIDs reveal nothing at all until you ask: a partial IMEI is still a head start for SIM-swap fraud.

Do I need an account?

There isn't one. No sign-in, no email, no analytics, no crash reporting, no attribution SDK. There's no dashboard anywhere with your name on it because there's no dashboard.

Why does it ask permission to track me?

Because allowing tracking is the only way iOS will reveal your advertising identifier, and showing it to you is the point. Specdeck doesn't track you and sends nothing anywhere. Same story with location: iOS requires location access before any app can read the name of the Wi-Fi network you're on. Every unlock sheet quotes the system prompt word for word first, so the real dialog holds no surprises.

Can I export this?

As JSON or Markdown, at three redaction levels. Redacted drops sensitive values entirely and is safe to paste into a bug report. Hashed turns them into one-way hashes, so you can tell two of your own reports apart without disclosing anything. Everything is verbatim, and asks you to confirm first, because that file contains your serial number and IMEI in plain text.

Is it on the App Store?

Not yet. Build it from this repo, or run the device report in your browser at specdeck.walhallaa.com — it works on any iPhone in Safari, no app required.

Under the hood

SwiftUI on iOS 26, zero third-party packages. The server is Node 22 and Hono, with node-forge and plist doing the PKCS#7 and property-list work — 27 tests, no framework.

  • The catalog is data. All 70 identifiers are values in one registry file, so there's one row view, one detail view and one set of tests instead of seventy screens that drift apart. Localization keys are derived from identifier ids, which means a typo would silently render as its own raw key at runtime — so tools/check-strings.mjs cross-checks the 557 strings against the Swift sources in both directions before a build ever runs.

  • "Not available" is never a blank cell. Every way of not having a value is a distinct case in one enum, carrying the reason and, where one exists, the action that changes it. A permission you can grant, a capability this build lacks, a door Apple closed, or a device that was asked and declined — four different answers where most apps show an empty string.

  • Two independent checks on the device's signature. openssl smime -verify confirms the signature actually covers the content; node-forge confirms the chain reaches a pinned Apple root, in-process, because the leaf certificate's common name contains the UDID and nothing carrying that may touch disk. Certificate expiry is deliberately ignored — Apple's documentation requires it, since device certificates are routinely long expired and iOS keeps using them.

Run it

# iOS app — needs Xcode with the iOS 26 SDK
open specdeck.xcodeproj

# Profile service
cd server
npm install
npm test        # 27 tests, no network required
npm run dev     # http://localhost:8080

The server needs a real HTTPS certificate to sign profiles — iOS shows a red "Unverified" banner otherwise, which users can't tell apart from an actual attack, so it refuses to serve an unsigned one rather than degrade quietly. See server/DEPLOY.md.

Contributing

The catalog is the easy place to start: add a line to specdeck/Core/IdentifierRegistry.swift, add its strings to specdeck/Resources/Localizable.xcstrings, and run node tools/check-strings.mjs — it will tell you exactly which keys you missed, in either direction.

Deploying your own instance needs a Cloudflare API token and a hostname; nothing else is secret. server/DEPLOY.md has the full walkthrough and server/.env.example lists every variable.

License & contact

MIT. Found a value Specdeck gets wrong, or an identifier it's missing — open an issue or email info@walhallaa.com.


Built by Murat Can Koç

About

iOS app that catalogs the 70 identifiers an iPhone can be asked for, sorted by what it costs to ask. Free, permission-gated, entitlement-gated, or sealed off by Apple — plus UDID, serial and IMEI via Apple's Over-the-Air Profile Delivery, which no app can read. SwiftUI, zero dependencies, Node profile service.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages