Secrets

Secrets are key-value pairs that store sensitive data like API keys, tokens, and passwords. Instead of hardcoding values into your workflows, you store them as secrets and reference them by name at runtime.

Managing Secrets

To manage secrets, open your workspace Settings and navigate to the Secrets tab.

Secrets are organized into two sections:

  • Workspace — shared with all members of your workspace
  • Personal — private to you

External workspace members count as workspace members for workspace-scoped secrets. They can use workspace secrets according to their workspace permission level, even though they are not members of your organization.

Adding a Secret

Type a key name (e.g. OPENAI_API_KEY) into the Key column and its value into the Value column in the last empty row. A new empty row appears automatically as you type. Existing values are masked by default.

When you're done, click Save to persist all changes.

Keys must use only letters, numbers, and underscores — no spaces or special characters.

Bulk Import

You can populate multiple secrets at once by pasting .env-style content into any key or value field. The parser supports standard KEY=VALUE pairs, export KEY=VALUE, quoted values, and inline comments.

Editing and Deleting

Click directly into any key or value cell to edit it. To delete a secret, click the trash icon on its row and save.

Using Secrets in Workflows

To reference a secret in any input field, type {{ to open the variable dropdown. Your available secrets are listed grouped by scope (workspace, then personal).

Select the secret you want to use. The reference appears highlighted in blue and is resolved to its actual value at runtime.

Execution log protection

When a saved secret is successfully substituted through a {{KEY}} reference, Sim masks exact, case-sensitive occurrences of its resolved value in log-facing content. This includes the editor's live block-log display, Logs Overview input and output, stored execution traces, log-read API responses, and the Logs block's Get Run Details output. Function and Agent span inputs, outputs, and errors, Agent thinking, and Agent tool-call arguments, results, and errors are protected. The replacement is normally shown as {{KEY}}.

Secret resolution and functional workflow behavior are unchanged: blocks, tools, and downstream steps receive the real runtime value. Stored functional execution data, workflow execution responses, streams, callbacks, block state, and snapshots are not rewritten. Log-facing views and read APIs receive a separate protected copy, so the Logs Overview Workflow Input and Workflow Output are masked without changing the underlying workflow result. Model requests receive another protected projection: exact secret values known to the run are replaced with {{KEY}} before model-visible messages, prompts, tool arguments, or tool continuations leave Sim.

Code that reads a secret straight off the runtime environment — environmentVariables['KEY'], environmentVariables.KEY, or const { KEY } = environmentVariables in JavaScript, environmentVariables['KEY'] or environmentVariables.get('KEY') in Python, $KEY or ${KEY} in shell — also activates masking, provided Sim can see the read in the code before it runs. A hardcoded literal never does: Sim has no way to know it came from a secret.

Direct reads are found by reading the code, not by running it, so recognition stops where the code stops being readable ahead of time. An unrecognized read is not masked, and does not appear under See usage.

Where a read is recognized, Sim reports it rather than trying to prove it is not one. Code that shadows the environment binding with its own object, overwrites a variable before reading it, or assigns to the name instead of reading it is still reported. Naming a secret costs only an exact value the code never emits; failing to name one leaves it unmasked. See usage can therefore occasionally list a secret the code had available but did not read.

Assigning to the injected binding does not change the stored secret — it is an ordinary object built from the run's payload and discarded when the run ends. Edit a secret under Settings → Secrets.

A read is not recognized when:

  • The name is built at runtime. environmentVariables[keyName], $@, ${!indirect}, eval, printenv, or a sourced file hide which secret is being read.
  • The read is of a different object. other.environmentVariables['KEY'] reads something that merely shares the name.
  • The read cannot be told apart from text. A $KEY inside single quotes or a quoted heredoc (<<'EOF') never expands, and Sim treats anything its scanner cannot place as not running.

Both masking and model-bound projection match only exact values in either case. Encoded, hashed, fragmented, or otherwise transformed versions are not matched, and a value assembled or emitted piece by piece cannot be matched at all — determining whether arbitrary code will eventually reveal a value is not decidable in general. Treat these as a safety net, not a boundary: do not deliberately return, print, or transmit secrets.

Copilot code execution

Copilot's Function and code-execution tools receive a saved secret only when their code explicitly contains a valid {{KEY}} reference. Direct environmentVariables.KEY access, shell $KEY, dynamic names, literals, and configured-but-unused secrets do not mount a value. Code execution requires workspace write access, and the caller must be allowed to use the secret — the same set a workflow resolves for them: your own Personal secrets, and Workspace secrets you hold an active grant on as a Credential Member or Credential Admin, which a workspace admin holds on every key. A secret you hold no grant on does not mount, and neither does one whose grant is revoked or still pending.

This matches what a workflow Function block already resolves for the same person, deliberately. Being able to run a secret is not normally the same as being able to read it: Credential Members can reveal a workspace secret under Settings → Secrets only when a Credential Admin has enabled Show value in logs and Chat. See usage remains visible only to that secret's admins, so a Credential Member using a secret in code is recorded for whoever can rotate it.

Headless surfaces use their saved Secret access setting:

  • Sim Chat block — under Show additional fields
  • Scheduled Tasks — in the task modal
  • Inbox — under Settings → Inbox → Secrets

Choose All secrets or Selected secrets. Existing configurations default to All secrets for compatibility. All secrets still means only secrets explicitly referenced with {{KEY}} that the execution actor may use; it never injects the full environment. Inbox messages from allowed external senders do not receive raw-secret access at all — an inbound message that Sim cannot match to a workspace member runs with no secret actor, so no {{KEY}} resolves for it.

Code receives the real authorized value at runtime. Before any Copilot-visible tool result is returned, exact occurrences of activated secret values are replaced with {{KEY}}; local side effects and runtime results are not rewritten. Encoded, hashed, URL-encoded, otherwise transformed, or network-exfiltrated values cannot be inferred and masked reliably, so code should not deliberately return, transform, print, or transmit secrets to unintended destinations.

Secret Details

Click Details on any secret row to open its detail view.

From here you can:

  • View the Key and reveal the Value when visibility is enabled; Credential Admins can edit it
  • Toggle Visibility — show the value unmasked in run output; see Visibility
  • Edit the Description — an optional note telling teammates what the secret is for. Workspace secrets only; a personal secret is not shared, so it has none
  • Manage Members — invite teammates by email and assign them an Admin or Member role
  • Open See usage — where this secret has actually been used

Click Save to apply changes, or Back to return to the list.

Visibility

By default, a secret's resolved value is masked everywhere Sim shows run output (see Execution log protection). For values that aren't actually sensitive — a non-secret shared base URL — that masking makes your own logs harder to read.

Show value in logs and Chat turns masking off for one workspace secret. With it on:

  • Run logs, Chat, and code output show the real value instead of {{KEY}}
  • Files a run writes with the value in them stay readable and attachable
  • The Secrets API list includes the value for this secret, so external agents can read it directly instead of scraping logs
  • Credential Members can reveal the value under Settings → Secrets, without gaining permission to edit it

The value becomes visible to anyone who can see this workspace's runs — including publicly shared log links and log exports, and regardless of member restrictions on the secret itself. Only turn it on for values you'd be comfortable printing in a log.

The switch applies to future runs only. Logs written while the secret was masked stay masked, and anything written while it was visible keeps the value even if you turn masking back on. If another secret holds the same value, that value stays masked — masking always wins a conflict. Workspace secrets only; the same people who can edit the description can flip it.

See usage

See usage lists the runs that resolved this secret: when it was last used, what used it (a workflow, the Sim agent, or an MCP server), how it was triggered, who it resolved under, and a link to the most recent run in Logs. Rows are grouped by day, so a workflow on a schedule reads as one row per day rather than thousands.

This answers the question worth asking before rotating a key: who has been using it, inside what, and how recently.

Only Credential Admins on a workspace secret, or the owner of a personal one, can see its usage. For everyone else the action is visible but disabled because the trail names workflows, people, and run IDs. Two people who each hold a personal secret under the same name see only their own runs.

Usage is recorded independently of execution logs, so it outlives them: logs expire under your workspace's retention setting, while the record of who touched a credential does not. It records what a run resolved, subject to the recognition limits under Execution log protection — a read Sim cannot attribute is left out rather than guessed at, so treat an empty trail as "nothing recognized," not proof a secret was never used.

Workspace vs. Personal

FeatureWorkspacePersonal
Who sees the nameAll workspace members, including external workspace membersOnly you
Who sees the valueWorkspace admins and that secret's Credential Admins; Credential Members when Show value in logs and Chat is enabledOnly you
Use in workflows and codeWorkspace admins and members with an active Credential Member or Credential Admin grantOnly you can use
Best forProduction workflows, shared servicesTesting, personal API keys
Who can editWorkspace admins and that secret's Credential AdminsOnly you

Among secrets available to the execution actor, the workspace secret takes precedence. An inaccessible workspace secret does not shadow an authorized personal secret.

Resolution Order

When a workflow runs, secrets resolve in this order:

  1. Workspace secrets are checked first, and always resolve against the identity running the workflow — the caller when one can be identified, otherwise the workspace's billing account. A run only sees the workspace secrets that identity is allowed to use.
  2. Personal secrets are used as a fallback, from whichever identity is running:
Run started byPersonal secrets come from
Clicking Run, or a personal API keyThe person running it
A workspace API key, schedule, webhook, or deployed chatThe workflow owner
A public API URL with no authenticationNobody — personal secrets do not resolve

The workflow owner is the fallback only where nobody can be identified but somebody in the workspace set the trigger up, since those workflows are usually built against the owner's own keys. A public URL can be called by anyone, so it never borrows a person's keys at all — put every secret such a workflow needs in Workspace.

If the workflow owner later leaves the workspace, the run keeps working: it resolves workspace secrets as normal and simply resolves no personal ones, so any block that needed a personal secret fails on its own with the missing key named. Move that secret to Workspace to fix it for good.

Best Practices

  • Use workspace secrets for production so workflows work regardless of who triggers them
  • Use personal secrets for development to keep test keys separate
  • Name keys descriptivelySTRIPE_SECRET_KEY over KEY1
  • Never hardcode secrets in workflow input fields — always use {{KEY}} references

Common Questions

Yes. Values saved under Secrets are encrypted before being stored in the database.
Yes. Functional workflow data is not rewritten, so the raw value can still reach downstream blocks and tools and can appear in workflow execution responses, streams, or callbacks if your workflow deliberately returns or prints it. Log-facing views and read APIs receive a protected copy after a successful {{KEY}} resolution. Before content is sent to a model, exact values from the run's authorized secret catalog are replaced with placeholders, but encoded or otherwise transformed values remain outside that protection.
Among secrets available to the execution actor, the workspace secret takes precedence and the personal secret is the fallback. An inaccessible workspace secret does not shadow an authorized personal value.
Whoever is running it, when that can be identified. Clicking Run or calling with a personal API key uses that person's personal secrets. A workspace API key, schedule, webhook, or deployed chat has no identifiable caller, so it falls back to the workflow owner's — those triggers are set up inside the workspace and the workflow is usually built against the owner's own keys. A public API URL with no authentication can be called by anyone, so no personal secrets resolve at all — those workflows run on workspace secrets only.
They keep running. Workspace secrets resolve as normal, because they are checked against the workspace's billing account rather than the owner. Personal secrets stop resolving, so any block that referenced one fails with that key named — move it to Workspace to fix it permanently.
Yes. Paste .env-style content (KEY=VALUE format) into any key or value field and the secrets will be auto-populated. The parser supports export KEY=VALUE, quoted values, and inline comments.
The workflow will fail at any block that references the deleted secret during execution because the value cannot be resolved. Update any references before deleting a secret.