Skip to content

Installers silently ad-hoc sign when TACET_SIGN_IDENTITY is unset #21

Description

@drycode

Both install-server.sh and install-client.sh build through swift/Packaging/build-app.sh, which falls back to an ad-hoc signature when TACET_SIGN_IDENTITY is empty:

if [[ -n "${SIGN_IDENTITY}" ]]; then
    codesign --force --deep --sign "${SIGN_IDENTITY}" ...
else
    echo "   using ad-hoc signature (-)"
    codesign --force --deep --sign - ...
fi

The echo is the only signal, and it scrolls past inside a long install. The install then reports success and --doctor passes, because codesign --verify --strict is satisfied by an ad-hoc signature.

What it cost

On 2026-08-04 a Developer ID signed bundle was installed at 14:12. An install-client.sh run at 14:17, in a shell without the variable set, rebuilt over it ad-hoc. Nothing indicated a downgrade had happened. The first notarization submission was then rejected:

The binary is not signed with a valid Developer ID certificate.
The signature does not include a secure timestamp.

Diagnosing that meant a round trip to Apple plus a log fetch, for a state the installer already knew about at build time.

Why it matters beyond the one incident

TCC grants key on the designated requirement. An ad-hoc DR is a bare cdhash, so every rebuild invalidates Accessibility and Microphone. That is exactly what #2 and the signing work exist to eliminate, and an unset environment variable silently puts you back on the old footing — currently true of the Studio install.

Suggested fix

Any of these, in rough order of preference:

  1. Resolve an identity automatically when the variable is unset — security find-identity -v -p codesigning returning exactly one Developer ID Application is an unambiguous default.
  2. Make the ad-hoc path opt-in (TACET_ALLOW_ADHOC=1) and fail otherwise, so the downgrade cannot happen by omission.
  3. At minimum, have --doctor report the signature type, not just that verification passed. codesign -dvvv exposes it as flags=0x10002(adhoc,runtime) vs flags=0x10000(runtime).

Related: the missing --timestamp in the same script, fixed in f14077e.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions