This is Peel's security policy: how to report a vulnerability, what happens after, and what is in scope. What Peel protects, and how, has a page of its own: SAFETY.md.
Report it privately on GitHub, with Report a vulnerability on the repository's Security tab, or email contact@tuguidragos.com with "Peel security" in the subject line.
Do not open a public issue, a discussion, or a pull request for a security bug. Do not post it anywhere public until the fix ships or 90 days have passed since your report, whichever comes first, as Coordinated disclosure explains.
Please include, as much as you have:
- The version of Peel and the build number, from About.
- Your macOS version and whether the Mac is Apple silicon or Intel.
- Which component: the app, the privileged helper, the Finder extension, the
peelcommand, or Sparkle. - What an attacker gains, and what they need to start with. State plainly whether the attack needs a local unprivileged process, an administrator account, or a user action.
- Steps to reproduce, and a proof of concept if you have one. A short script or a small sample app is worth more than a description.
- Anything you want credited, or that you would rather stay anonymous.
Send it in plain text. Attachments are fine. Encryption is available on request; there is no published key yet, so ask and one will be set up before you send anything sensitive.
If you get no reply within 5 days, resend. Mail gets lost, and a solo maintainer is a single point of failure.
| Stage | Target |
|---|---|
| Acknowledgment that your report arrived | 2 working days |
| First assessment: confirmed, not confirmed, or need more detail | 7 days |
| Fix released for a confirmed high-severity issue | 30 days |
| Fix released for anything else confirmed | 90 days |
| Public disclosure | when the fix ships, or 90 days from your report, whichever is first |
These are targets, not contractual promises. If a fix is going to be late, you will be told why and given a new date, not silence.
Peel follows coordinated disclosure.
- You report privately. The issue stays private while it is fixed.
- 90 days after your report, you are free to publish, whether or not a fix exists. You do not need permission, and asking for an extension is a request, not a condition. 90 days is a common deadline, Google Project Zero's among them. CERT/CC publishes sooner, 45 days after a report, and CISA may publish 45 days after first trying to reach a vendor that does not answer; the Zero Day Initiative gives a vendor 120 days.
- If the bug is being exploited in the wild, that clock is not useful. Say so in your report: the fix and the advisory then go out as fast as they can be built, and disclosure happens early on purpose, so people can protect themselves.
- If you need longer than 90 days for your own reasons, say so, and that is respected.
- The advisory names you as the reporter, with a link if you want one, unless you ask not to be named. That is the default, not a favor.
There is no bug bounty. There is no money. There is credit, a fast fix, and a straight answer.
Peel is a single line of releases. Only the latest release gets security fixes.
| Version | Supported |
|---|---|
| Latest release | Yes |
| Anything older | No: update |
There are no long-term support branches and there will not be any. If you are on an older build, the fix is to update.
Peel requires macOS 26 or later. Issues that only reproduce on an unsupported macOS version are out of scope.
Peel is not sandboxed and is distributed outside the Mac App Store. Releases are signed with a Developer ID and notarized by Apple. It has four pieces of its own, and carries Sparkle, which updates it:
- Peel.app: the interface, running as you.
- com.tuguidragos.Peel.Helper: a system daemon registered with
SMAppService, running as root, reachable only over an XPC Mach service. - PeelFinder: a sandboxed Finder Sync extension that opens
peel://open?path=. - peel: a command-line tool inside
Peel.app/Contents/Helpers. It never talks to the helper. - Sparkle: the framework in
Peel.app/Contents/Frameworks, with its programs Autoupdate and Updater.app, which install an update of Peel once the person chooses it.
Anything that gets code or file operations to run with privileges the attacker did not already have, and anything that destroys data that cannot be recovered.
The privileged helper. This is the part that matters most.
- Any way to get the helper to act for a program other than Peel. The helper serves an app with Peel's identifier, signed with Developer ID by Peel's team, that cannot be debugged and is no older a build than the helper itself, wherever that copy sits. That includes defeating this code-signing requirement on the XPC peer, or replaying or forging a connection.
- Any way to get the helper to act for an account that is not an administrator. Every account on the Mac can reach its Mach service, by design; the helper answers administrators only, checked when a connection opens and again with each message.
- Any way to get the helper to touch a path outside the locations
PrivilegedPathPolicyallows: path traversal,..handling, symlink or hardlink following, mount tricks, firmlinks, or a race between the check and the file operation (TOCTOU). - Any way to use the restore path to write attacker-controlled content into a location that a root process later loads code from.
- Downgrade attacks: getting the helper to answer a copy of Peel that is older than the helper, unsigned, signed by anyone else, or debuggable. A copy as new or newer, signed the same way, is served wherever it sits, by design.
- Argument injection or unexpected behavior in the operation that runs
launchctlfor a launch daemon (bootstrap, bootout, kickstart, enable, and disable), or in the one that moves the helper's own ledger to the Trash for Remove Peel. - Anything that leaves a root daemon installed, running, or reachable after Remove Peel, or that lets an account that is not an administrator install, replace, or remove it. A Peel dragged to the Trash leaves its helper registered, as GUIDE.md says, until it is put back and removed with Remove Peel.
Destruction of data.
- Any way to get Peel to delete something permanently that it should have moved to the Trash. The few things Peel deletes, or can't undo, by design are listed in SAFETY.md.
- Any bypass of
RemovalGuardthat reaches anything SAFETY.md lists under "What Peel will never remove". - Any bypass of the user's Exclusions.
- App Reset touching anything it did not list, taking an app's own data (its
Application Supportfolder, group containers, or application scripts) without being asked, or touching a container'sDocumentsorAutosave Information. - Duplicates taking the last remaining copy of a group.
The other components.
- Path injection, argument injection, or unintended navigation through the
peel://URL scheme, from the Finder extension, from any other process on the Mac, or from a web page, and through Peel's other ways in: an app dropped on it or opened with it, and the actions it gives Shortcuts. - A sandbox escape in the Finder Sync extension.
- Hijacking the
peelcommand, or getting it to perform an operation that should require the helper. - Update-feed handling: Peel fetches update feeds whose addresses come out of each scanned app, a
Sparkle feed in its
Info.plistor an Electron app'sapp-update.yml, and for an update that waits, the page of release notes the feed names, which it reads as HTML, Markdown, or plain text. A malicious feed or page that causes memory corruption, an exploitable crash, a file write, or code execution, or that leaks data off the Mac, is in scope. - Leaking the list of a user's installed apps, file paths, or scan results off the Mac, beyond what PRIVACY.md describes.
- Peel's own updates: getting Peel to install, or to offer, an update that is not signed as Peel's (with Peel's update key, or, as Sparkle allows when that key changes, in a disk image signed with Peel's Developer ID), one older than the copy installed, or one from anywhere but its signed feed. The one exception is Sparkle's design: a feed whose signature has kept failing for 20 days is read without its release notes or its critical mark, so that a changed key can still reach every copy, and what it offers installs only when it is signed as above. Peel updates itself with Sparkle, so a flaw in Sparkle that reaches Peel is in scope too, and it is passed on to the Sparkle project.
What Peel reads, runs, and writes.
- Files from apps, projects, and disks Peel doesn't trust, which it reads to decide what is what:
other apps' property lists and product files (
product-info.json,product.json), the headers of their programs (Mach-O), the directory of a ZIP archive, read without extracting it, the first line of a crash report, a Git repository's index and itsconfig, a launch job's file, a browser's native messaging manifest, the package definitions Homebrew and its taps give, whose paths an uninstall lists, Homebrew's ownbrew.envfiles, Terminal's preferences, the settings files of the tools whose caches Developer lists (.npmrc,.yarnrc,.yarnrc.yml, pnpm'sconfig.yaml, Go'senv), which say where a cache was moved, the shell startup files, read after a removal for the lines that still name what moved, and the database macOS keeps of where downloads came from, read forpeel inventoryand Export. One that causes memory corruption, an exploitable crash, or a wrong answer about what may be removed is in scope. - The programs Peel runs with what a scan found:
defaults,launchctl,tccutil,pkgutil, andpluginkit, given an app's, a package's, or an extension's identifier, a launch job's label, or a path, andbrew, including one chosen in Settings. Getting one to run with arguments an attacker chose, or getting Peel to run another program, is in scope. - What Peel writes besides moving files, each listed in
SAFETY.md: the Tweaks, which also restart the
Dock, Finder, Control Center, or Window Manager with
killall; the settings the Terminal page writes for Terminal, the shell, ssh, and Git; the Dock's lists, when an uninstall takes an app's icon out; the preference domains it forgets withdefaults delete; the copies of an app's settings a reset saves and puts back; and the Time Machine mark Build Artifacts sets. Getting any of them to write anything but what the user chose, or to write it anywhere else, such as through a link, is in scope.
Peel's website and Homebrew tap.
- peel.tuguidragos.com, which GitHub Pages serves from this repository's
docs/folder, and the Homebrew tap,TuguiDragos/homebrew-tap, whichbrew install --cask tuguidragos/tap/peelreads. A way to change what either shows or installs, or to send its downloads anywhere but this repository's releases, is in scope.
Not because they do not matter, but because they are not bugs in Peel.
- Anything that needs root to begin with. If the attacker is already root, they can do all of this without Peel.
- Anything an administrator can already do on macOS.
/Applicationsis writable by any administrator by design. An administrator who can already delete an app has gained nothing by using Peel to delete it. Escalation from administrator to root without an authentication prompt is in scope, beyond what the helper does for an administrator by design once it is approved: moving items in the foldersPrivilegedPathPolicyallows to the Trash and back, and runninglaunchctlfor another developer's launch daemon. An administrator doing what administrators do is not. - Peel deleting what the user told it to delete. The confirmation, the preselection rules, and the Trash are the safety net. A user who selects a checkbox and confirms is not a vulnerability. A bug that makes Peel select the checkbox for them, or that removes something not shown, is.
- Bugs in macOS itself. Report those to Apple at https://security.apple.com/submit/. See https://support.apple.com/en-us/102549. They are not fixable here.
- Bugs in third-party apps that Peel merely lists, scans, or reports on. Report those to the app's own developer.
- Physical access, evil-maid, and unlocked-Mac scenarios.
- Social engineering of users, of the developer, or of anyone else.
- Self-inflicted configurations: SIP disabled, Gatekeeper disabled, a modified or re-signed build of Peel, running as root on purpose.
- Missing hardening with no exploit path. Peel is deliberately not sandboxed: it has to read the whole disk to do its job. A report saying "not sandboxed", "hardened runtime flag X is absent", or "library validation could be stricter" needs a working attack to be actionable.
- Automated scanner output with no proof of concept.
- Denial of service that only affects the person running Peel, and filling your own disk.
- The tuguidragos.com website, other than Peel's own site above. Separate thing. Email the same address, but do not expect it to be treated as a Peel report.
If you are not sure which side of the line something falls on, send it. Getting it wrong in the direction of reporting is the right mistake.
Test on a Mac you own, with data you can afford to lose. Use a virtual machine if you can.
Do not test against other people's machines. Do not access, copy, or keep anyone else's data. If you hit real personal data during testing, stop, delete what you have, and say so in the report. Do not run anything that degrades service for other people. Do not use a finding to extort.
If you follow this policy in good faith:
- Your research is authorized. No legal action will be initiated or supported against you for accidental, good-faith violations of this policy.
- No claim will be brought against you for circumventing technical controls in Peel in the course of that research.
- If a third party takes legal action against you for work done in compliance with this policy, it will be made known that your actions were authorized.
Two limits, stated plainly because pretending otherwise would be dishonest:
- This only covers claims that are the maintainer's to bring. It does not bind Apple, does not bind the developers of any other app you touch while testing, and does not bind anyone else.
- It does not override the law. You are still expected to comply with it.
If you are uncertain whether something you are about to do is covered, ask by email first.
This safe harbor is adapted from the disclose.io model terms, which are published under CC0: https://github.com/disclose/dioterms.
Each fixed issue gets a GitHub security advisory, and the release notes link to it.
If an issue warrants one, a CVE will be requested through GitHub Security Advisories: GitHub is a CVE Numbering Authority for open source projects hosted on GitHub. You are welcome to request the CVE yourself instead, and to be named in the record; say so in your report. If you would rather not wait, MITRE also takes requests directly.
One person reads that mailbox. English only.