If you find a security issue in Peekly, please don't open a public GitHub issue. Email the maintainer directly:
π§ romario.sobreira@hotmail.com
Please include:
- A description of the issue
- Steps to reproduce (a minimal HTML page is ideal)
- The browser version and OS
- Optionally a proof-of-concept video or screenshot
You'll get an acknowledgement within 5 days. Critical issues are patched within 14 days, lower severity within 30 days. Once a fix is shipped, a credit (or anonymous note, your choice) lands in CHANGELOG.md under ### Security.
Only the latest published version on Chrome Web Store and GitHub Releases is supported. Older versions don't get backported fixes.
| Version | Supported |
|---|---|
| 0.2.x | β |
| 0.1.x | β |
- Page-supplied data is treated as untrusted. Every value read from React fiber trees (component names, props, source paths) or from DOM attributes is rendered via
textContentβ neverinnerHTML. There is noeval, nonew Function, no dynamic<script>insertion, no inline event-handler attributes set from data. - Cross-world isolation is respected. The two content scripts (ISOLATED + MAIN world) communicate only via
window.postMessage, and both sides validateevent.source === windowanddata.source === 'react-picker'(the internal namespace). Nochrome.runtimechannel is exposed to the page. open-editorURLs are whitelisted. The service worker only forwards URLs whose protocol is in a known editor list:vscode:,vscode-insiders:,cursor:,webstorm:,idea:,pycharm:,subl:. Any other URL is rejected before it reacheschrome.tabs.create. This means even if our isolated world were compromised, it could not pivot to opening arbitraryhttp(s)tabs (phishing, malware download).- No network egress. Peekly never calls
fetch, never opensWebSocket, never usesXMLHttpRequest,navigator.sendBeacon, or any other network API. All processing is local. This is enforceable: search the source tree for those identifiers and you'll find none in production code. - Minimal storage. Three user preferences (
enabled,autoOnLocalhost,editor) live inchrome.storage.local. No PII. No telemetry. No remote identifier. No analytics SDK.
- A malicious extension already running in the same browser. Other extensions can manipulate the same page; Peekly assumes user-installed extensions are trustworthy.
- The user enabling Peekly on a phishing or hostile site. Peekly is an inspector β it reads page state. The page is the threat surface, not Peekly. The same caveat applies to React DevTools.
- Bugs in Chrome's own sandbox or the V8 engine.
- Supply-chain compromise of
@crxjs/vite-plugin,@resvg/resvg-js, or any of our build-time dependencies. We pin versions viabun.lockbut cannot audit upstream code per release. Build reproducibility (below) is the recourse.
| Permission | Risk | Justification |
|---|---|---|
<all_urls> (host_permissions) |
High in principle | Required by the content-script architecture: the inspector must be able to attach on any site the user chooses. The picker is off by default on every site except localhost / 127.0.0.1 / *.localhost. Users opt in per-site via the popup toggle. Page content is read locally but never transmitted. |
storage |
None | Three booleans/enums. |
activeTab |
Low | Activate the inspector on the user's currently focused tab when triggered from the popup. |
Permissions Peekly does not ask for, on purpose: tabs (full tab access), webRequest (network sniffing), cookies, clipboardRead, clipboardWrite (clipboard is accessed via the standard navigator.clipboard.writeText API that requires a user gesture), downloads, notifications, identity.
Every release is built from the public main branch by GitHub Actions on a vX.Y.Z tag push. The build environment is:
- Ubuntu latest (GitHub-hosted runner)
- Bun latest
- Dependencies frozen via
bun.lock
To reproduce a release locally and verify the artifact:
git fetch --tags
git checkout vX.Y.Z
bun install --frozen-lockfile
bun run gen:icons
bun run build
shasum -a 256 dist/assets/*.jsCompare the resulting dist/ against the peekly.zip attached to the matching GitHub Release. Any deviation should be reported per the procedure at the top of this document.
Two issues caught during a pre-release audit, fixed before tag:
- XSS via crafted component names in the contextual tooltip. The tooltip rendered owner-chain entries, current-element labels, and a11y warnings via
innerHTMLtemplate literals containing values from React fibers. A page could rename its components viadisplayNameto inject markup that would execute in our isolated content script. Fixed by replacing every dynamicinnerHTMLwithcreateElement+textContent. Severity: medium (limited blast radius β isolated world only β nochrome.*API exposed to attacker code). - Open-redirect via the
open-editorruntime message. The service worker accepted any URL string and forwarded it tochrome.tabs.create. Combined with the XSS above, an attacker could open arbitrary tabs (phishing). Fixed by parsing the URL and rejecting any protocol not in the editor whitelist. Severity: low (depended on the XSS to be exploitable).
Initial release. Manual review by author. No external audit.
(empty β first finder, your name will go here)