# The exposure check before a public link Before an app can be opened by anyone with a link, Qaldy questions a throwaway copy the way a stranger would. What it asks, what blocks a public link, and what it cannot find. URL: https://docs.qaldy.com/guides/exposure-check/ Most apps never need a public link: people open them behind your company login. A **form** or a booking page sometimes does. That is the moment an app stops being something only your people can reach, so Qaldy checks it first. The **exposure check** loads a throwaway copy of the app in a sandbox and asks it questions the way a stranger would: with no sign-in, as the lowest role, with hostile text and with huge input. What came back is judged by fixed rules. It takes about 20 seconds. :::note It never touches your real data The copy runs in the runtime host's sandbox with a database of its own. A finding holds a status, a content type and a size, never a response body, a record, a header value or a token. ::: ## Where you see it Open the app and look for **Exposure check**. **Run the check** starts it (owners and editors only; anyone who can view the app can read the result). It also runs by itself after a deploy and from the share dialog. Under **Public link** in the share dialog you see why a link is ready or not. ![The Exposure check card on an app page: no problems found inside the workspace, public link needs a form, all ten checks, and when it ran.](https://docs.qaldy.com/screens/exposure.webp "The Exposure check card on an app page. Sample data.") ## What it asks | Check | What it does | |---|---| | Sign-in is required | Opens every route it can find with no sign-in, and as the lowest role (viewer), and compares the answer with the owner’s. | | No records without sign-in | Plants a marker record in the throwaway copy’s database and looks for it in answers to a stranger. | | No secrets or tokens in answers | Sends fake credentials and looks for them in the answer; looks for the shape of real keys, and for stack traces and file paths. | | No open cross-site access | Asks the way another website would, and flags answers that let any site read them, or read them with the visitor’s sign-in. | | Safe browser headers | Looks for a Content-Security-Policy, content-type protection and framing protection on pages. | | Common injection attempts fail | Puts hostile text in every query name and form field and looks for SQL errors, reflected script and server errors. | | Undeclared hosts stay blocked | Checks that an address the app never declared stays blocked. | | Oversized input is handled | Sends very large input and checks that the app refuses it instead of failing. | | No writes without sign-in | Tries to write with no sign-in and flags a write that is accepted. | | Only declared tables | Checks that the tables the code uses are the tables the manifest declares, and that none uses a reserved name. | Each finding says which route, what happened and how to fix it, in plain words. **Copy for your coding agent** puts the findings on the clipboard in a form an agent can act on. ## What decides | Result | Meaning | |---|---| | **Blocked** | At least one *high* finding: for example records came back to someone who was not signed in, or an answer held something shaped like a secret. A public link cannot be turned on. | | **Review** | At least one *medium* finding, such as a page that lets any website read its answers. A person should look. | | **Clear** | Nothing that stops a public link. | For a link to be turned on, the check must have **finished on the current version**, and it must be less than 24 hours old. If the app changed, or the last check is older, run it again. If the check could not run, a public link waits: nothing is guessed. A sample app with no code has nothing to ask and passes, but the typed confirmation below still applies. Turning on **Anyone with the link** then asks you to **type the app's name**. Capital letters do not matter. Only an admin can turn it on, and only for apps whose workspace policy allows it. ## It also moves the Trust Score The result is folded into the [Trust Score](https://docs.qaldy.com/concepts/approvals/) as a report-only check, **Exposure probe passes**. A high finding keeps the score below the publish line, and a medium finding keeps it in Review until a person has looked. No check, a skipped one or one that could not run changes nothing. ## What it cannot find It is a **black-box** check of what an app answers, not a review of its code and not a penetration test. It finds the common, expensive mistakes: a route that forgot to ask who you are, an admin page a viewer can open, a stack trace in an error, a wildcard CORS header. It does not find a flaw it has no route to, a mistake in the app's logic that looks fine from outside, or anything about the platform beneath the app (the [gate](https://docs.qaldy.com/concepts/gate-and-secrets/) and the [sandbox](https://docs.qaldy.com/concepts/sandbox/) are what stand there). Passing it means "nothing it tried got through", and nothing stronger. ## Over the API and in the log `GET /v1/apps/{id}/probe` returns the last check of the current version and whether a public link may open; `POST` on the same path runs it again (an owner or editor; one manual run every 30 seconds per app). Running it is an [audit row](https://docs.qaldy.com/concepts/audit/). See [Share it](https://docs.qaldy.com/getting-started/share/) for the rest of sharing.