Your security review will be short.
There is no server, no database and no network call to assess. This page is the evidence, including the parts that are not flattering.
Where your data lives
Each macro stores one JSON document in its own configuration parameter. That parameter is part of the page, exactly like any other macro parameter, and it travels with the page wherever the page goes.
The consequence worth spelling out: the app has no copy of anything. There is no database to breach, no export to request, no retention period to agree and no deletion request to process, because there is nothing held anywhere except in your own Confluence content.
- Page restrictions apply, unchanged — there is no second permission model
- Page history records macro changes like any other page change
- Copy, move, templates, space export and trash restore all work with no code on the app’s side
- Uninstalling removes the app; your page content is untouched
Getting your records out, with or without us
Uninstall and the macros stop rendering: Confluence shows its placeholder and the stored document stays in your page source, structured and readable. That is the whole of the lock-in, and it is worth being precise about it rather than leaving “your data lives in the page” as a reassurance.
Each record is one JSON document under a single macro configuration parameter, carrying a schema version. Ask and we will send you the schema, so your own team can turn every record back into a table without the app and without us.
Change control
Forge applies a minor version to installed sites without asking. A change that adds a scope or an external permission does not apply until an administrator approves it, and a change to remotes does in most cases — this app declares none of those, so any future version that did would stop and ask you first.
What an unapproved update can do: change the app’s own code. What the macros show, what they write into a page when an author saves, and what they log. It cannot reach anything the app does not already have permission to reach, which is nothing outside the page — but within that, it arrives without asking.
And how it gets there. The vendor deploys to production by hand, from its main branch, after automated checks have passed on that commit. No automated system holds a credential that can deploy. That is a release procedure, not a technical lock. If four eyes on every production change is a control your process depends on, ask for it in writing before you install, not after.
What the app asks for
| OAuth scopes | None. permissions.scopes is an explicit empty list. |
|---|---|
| Remote services | None declared. |
| External permissions (fetch, egress) | None declared. |
| Forge KVS / app storage | Not used at all. |
| Web, scheduled and product triggers | None declared. |
| Connect modules or Connect key | None declared. |
| Functions | Three, and only three: one PDF/Word export handler per macro. None of them performs any I/O. |
A page view runs no function at all: the app declares no resolver on the view path, so there is nothing to invoke, however many macros sit on the page. That follows from the manifest, which you can read above — it has not been measured on a live site with twenty macros, and we would rather you knew which of the two this is.
Designed to qualify for Runs on Atlassian — a claim you can inspect.
The app runs entirely on Atlassian’s infrastructure, holds no data of its own and calls nothing external. Those are the egress properties the Runs on Atlassian badge describes, and they are true today.
One criterion is unconfirmed, and we would rather you heard it here. Atlassian also asks that an eligible app use data-residency-enabled Forge storage, or app entity properties. This app uses neither — it stores nothing outside the page’s own macro configuration, which is why there is no residency question to answer in the first place. Whether Atlassian treats that as meeting the criterion is untested.
The badge itself has not been granted. Atlassian awards it against
forge eligibility, run on a production deployment, and that has not
happened yet. When it has, this page will say so and name the date.
The questions your reviewer is going to ask
Atlassian’s Privacy and Security questionnaire, answered against the code rather than from memory.
| Question | Answer | Why |
|---|---|---|
| Does the app store end-user data outside Atlassian? | No. | No Forge storage, no remotes, no external permissions. The only persistence is the macro’s own configuration parameter. |
| Does it process end-user data outside Atlassian or the browser? | No. | Rendering is pure and happens in the Forge sandbox. The configuration dialog runs in the browser. |
| Does it log end-user data? | No, with one narrow exception. | The app logs the fact that a JSON parse failed, and the key names — never the values — of an unrecognised export payload. The exception: when stored text is not valid JSON, the JavaScript parser’s own error message can quote a short excerpt of that text, and the app logs that error. It takes a damaged document to happen at all. Two Forge settings could widen that, and they are the vendor’s to switch on rather than the code’s: front-end logging, which would capture the same excerpt on every page view of a damaged macro, and log export, which sends app logs to a vendor’s own tools outside Atlassian. Neither is enabled, and we will say so in writing. |
| Does it expose any remote REST API? | No. | No web triggers, no scheduled triggers, no product triggers, no Connect modules. |
| Does it share data with third parties or sub-processors? | No, and there are none. | There is no infrastructure of the vendor’s own that customer data ever passes through. |
| Does it retain data after uninstall? | No. | The app has no storage of its own, so it has nothing to retain. |
| Does it access personal access tokens, passwords or shared secrets? | No. | It requests no OAuth scopes, so it has no credential to use and nothing to ask for. |
| Does it transfer EEA data outside the EEA? | No. | Data typed into a macro never leaves the Confluence page it was typed onto, wherever that instance is hosted. |
| Can I find macro content when answering a subject access or erasure request? | Not through Confluence search. | Macro configuration is not opted into the search index, so a search for a person’s name can miss a page that names them in a review record — and review records routinely name the chair, the attendees and action owners. Page permissions, page export and space export all still reach it. Not yet verified on a live site. |
| Does it apply privacy-enhancing technologies? | No — and that is the point. | Input is stored and rendered back exactly as typed, inside the same page and subject to the same page permissions as everything else on it. That is the privacy posture, rather than a mitigation applied on top of a riskier default. |
A tripwire in the build, and an honest account of what it cannot see.
“Nothing leaves Atlassian” is a property of the source tree, not of anybody’s memory, so
it is asserted on every build. A sweep walks the manifest and every source file and fails
if it finds a remote, an external permission, a non-empty scope list, a trigger, a
Connect module, a fetch, an XMLHttpRequest, a dynamic import,
an eval, a Forge storage import, or a URL in runtime code. Nothing is
hand-listed, so a new file cannot be added outside its reach.
Much of it has been deliberately broken and watched to fail, each mutation recorded: an
external fetch permission in the manifest, a real OAuth scope, a fetch call
in several disguises, an XMLHttpRequest, a forbidden Forge API import, a
dynamic import() and an eval. Every one of them failed the
build, and every one was restored.
No mutation is recorded for the checks on remotes, triggers, Connect modules, Confluence and Jira API calls, or absolute URLs. Those checks pass, and nobody has watched them fail — which is a weaker thing, and the difference is worth having in front of you rather than behind you.
And its accepted limit, stated so it is not mistaken for a guarantee: this is a token sweep, not a resolver. It cannot see through code that assembles a name at runtime. No token-based tool can. What it does guarantee is that nothing in the tree spells one out — in code, in a string, in a template literal or in a regular expression. It exists to catch the honest mistake, and to make the dishonest one impossible to introduce quietly.
What has not been done
Stating this is the point of the page. A security section that lists only strengths is not evidence of anything.
- No third-party penetration test
- No CAIQ Lite questionnaire
- No SOC 2, ISO 27001 or other formal compliance certification
- No formal accessibility audit, and no VPAT
- No Runs on Atlassian badge yet — see above
What there is instead is an app with no server, no database and no network calls, whose entire attack surface is what Confluence already exposes — and the whole of it described on this page rather than summarised. The source is proprietary and the repository is private, so we cannot offer you a source review; what we can do is answer any question on this page in writing.
Accessibility, described rather than claimed
These are decisions visible in the code. They are not an audit.
- Colour never carries meaning alone — the letter is inside the RACI label, the word is inside the RAG lozenge, and an overdue action is red and carries the word “Overdue”
- Every colour, space and radius is an Atlassian design token, so the macros follow the reader’s theme
- No two controls in a dialog share an accessible name — fields are named for their row, and each row carries its own heading
- Confirmations are inline, never a second modal competing with the host dialog for focus; the safe button is first and takes the focus
- Character limits count user-perceived characters, so a cap cannot cut an emoji in half or drop a combining mark
- Wide tables scroll inside the macro, never the page, and every table carries a label
And the limits, which are real
These come from the UI Kit components the macros are built from, and are published rather than left to be discovered.
- Tables have no row headers — the component offers no way to mark one
- The scroll area around a wide table cannot be reached by keyboard alone, and its region has no name
- Nothing that appears mid-edit is announced to a screen reader: no component exposes a live region
- Focus cannot be moved programmatically, so removing a row does not move the focus anywhere sensible
- A macro title is always a level-three heading, whatever the page around it is doing
The full account, with what each one means in practice, is in the Confluence administrator’s guide and the reader’s guide.
One scope note, because it matters: the statements above describe the
app. This website is a separate thing. It is checked with an automated
accessibility test — every route, in both themes, at desktop and phone width, with
every disclosure opened first, run against the built site with
npm run a11y. It last ran on 4 October 2026, with no violations. An
automated test finds what a machine
can see and nothing else: it cannot judge whether a heading is the right heading or
whether alt text describes the right thing. Neither the app nor the site has had a
human audit.
If you find a problem in this app.
There is no separate security address yet, and that is a gap. A security report and a bug report are not the same request, and they should not share a queue. Until one exists, send it to support@itsm-ltd.com marked security, and it will be read as one.
We acknowledge reports within 2 business days, and a good-faith report is never met with a legal threat. If something in this app affects your data we will tell you what we know and when we knew it. Full remediation targets by severity, and incident notification timeframes, are in the Cloud Security Statement §8.
And this website
Separate from the app, and worth stating because a security review will ask. This site is static files. It runs no analytics, sets no cookie, embeds nothing, loads no font and makes no request to any other host — a build-time sweep of the generated output fails the build if it ever does. The one thing it stores is your light or dark theme choice, in your own browser, and nothing reads it but the page you are on.
Where ITSM Ltd stands in data-protection terms. The app sends nothing to us and we hold no copy of anything it touches: whatever your people type into a macro stays in your Confluence instance, under your own controls. The one exception is transient: the App's three export functions process a macro's content in memory, on Atlassian Forge compute we engage, when a page is exported to PDF or Word, and retain nothing afterwards. For that processing, and only for that processing, ITSM Ltd acts as your processor; storage of the content itself remains Confluence's, under your own agreement with Atlassian. The full position is set out in the Data Processing Agreement.
The other exception, and it is this site rather than the app. If you press “Tell me when it lists”, your own mail client sends us your address and a person keeps it in a file until the day the app lists. Then it is deleted. That is the only personal data ITSM Ltd holds because of anything on this site.
Read the formal documents. The paragraphs above are a plain-English summary, not a substitute. The Privacy Policy, End User Terms, Cloud Security Statement, Support and Maintenance Description and Data Processing Agreement are what actually governs this, at serviceaccord.itsm-ltd.com/legal.
Nothing on this page has to be taken on trust.
No OAuth scopes, no remote services, no storage of its own, and every answer on this page traceable to a line of the manifest or the code.
Not listed yet: it goes to the Atlassian Marketplace as a free app once it has passed review. The button opens your own mail client. You hear once, on the day it lists, and never again. What is in 2.7.0