Skip to content

Commit cef6563

Browse files
committed
fix(credentials): close the PR-wide audit findings
Docs describe credential-only Telegram and Typeform actions and the issuer's query/fragment refusal, PagerDuty and Grain copy name every token type that works, Granola accepts a key whose note scope an admin turned off, a GitLab reply that isn't a token lookup reports the provider, and Semrush's catalog entry matches staging exactly.
1 parent d141457 commit cef6563

10 files changed

Lines changed: 24 additions & 10 deletions

File tree

‎apps/docs/content/docs/integrations/aws-credentials.mdx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ To rotate a key, create the new key in AWS, reconnect the credential with it, co
5858
Keyless roles need two things on a self-hosted deployment:
5959

6060
- `WORKLOAD_IDENTITY_SIGNING_KEY`: a PKCS#8 PEM RSA private key that signs Sim's tokens.
61-
- An issuer AWS can reach over the public internet: an `https` URL on the default port, served by a certificate from a public CA. It defaults to `<NEXT_PUBLIC_APP_URL>/oidc/workload`; set `WORKLOAD_IDENTITY_ISSUER` to pin it. Trust policies reference this URL, so never change it once roles trust it. Sim keeps keyless off when the issuer isn't `https` or names a port, because AWS can't use it.
61+
- An issuer AWS can reach over the public internet: an `https` URL on the default port, served by a certificate from a public CA. It defaults to `<NEXT_PUBLIC_APP_URL>/oidc/workload`; set `WORKLOAD_IDENTITY_ISSUER` to pin it. Trust policies reference this URL, so never change it once roles trust it. Sim keeps keyless off when the issuer isn't `https` or names a port, query, or fragment, because AWS can't use it.
6262

6363
Generate a key with `openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048`.
6464

‎apps/docs/content/docs/integrations/telegram.mdx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ The [webhook setup video](https://www.youtube.com/embed/9oKcJtQ0_IM) also demons
2727

2828
1. Add the bot to the group and grant the permissions needed by the action.
2929
2. Obtain the group's numeric chat ID from a bot message update, such as the trigger's `message.raw.chat.id`. Group IDs can be negative.
30-
3. Add a Telegram action block, select **Send Message**, and set **Bot Token**, **Chat ID**, and **Message**.
30+
3. Add a Telegram action block, select **Send Message**, choose a **Telegram Credential** (a saved bot token), and set **Chat ID** and **Message**.
3131
4. Run the workflow and verify the message in the group.
3232

3333
The [group messaging video](https://www.youtube.com/embed/AG55LpUreGI) demonstrates the block configuration. Bot privacy settings affect which group messages Telegram delivers; receiving a command addressed to the bot can help verify the trigger before changing those settings.

‎apps/docs/content/docs/integrations/typeform.mdx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { ReferenceDetails } from "@/components/ui/reference-details"
1010

1111

1212
{/* MANUAL-CONTENT-START:intro */}
13-
Use [Typeform](https://www.typeform.com/) in Sim to retrieve form responses, download submitted files, and get form insights. Switch to trigger mode to start a workflow when a form is submitted. The integration requires an API key.
13+
Use [Typeform](https://www.typeform.com/) in Sim to retrieve form responses, download submitted files, and get form insights. Switch to trigger mode to start a workflow when a form is submitted. Actions sign in with a saved Typeform credential (a personal access token with the `forms:read` scope); the trigger takes its own token.
1414
{/* MANUAL-CONTENT-END */}
1515

1616
## Use the block [#usage-instructions]

‎apps/docs/content/docs/platform/self-hosting/environment-variables.mdx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ Saved AWS and Databricks credentials can trust Sim through OpenID Connect instea
167167
| Variable | Description |
168168
| --- | --- |
169169
| `WORKLOAD_IDENTITY_SIGNING_KEY` | PKCS#8 PEM RSA private key that signs Sim's workload-identity tokens: `openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048` |
170-
| `WORKLOAD_IDENTITY_ISSUER` | Issuer URL clouds trust. Defaults to `<NEXT_PUBLIC_APP_URL>/oidc/workload`; must be `https` on the default port and reachable from the public internet, or keyless stays off. Never change it once trust policies reference it. |
170+
| `WORKLOAD_IDENTITY_ISSUER` | Issuer URL clouds trust. Defaults to `<NEXT_PUBLIC_APP_URL>/oidc/workload`; must be `https` on the default port, with no query or fragment, and reachable from the public internet, or keyless stays off. Never change it once trust policies reference it. |
171171
| `WORKLOAD_IDENTITY_PREVIOUS_KEY` | A second published key (private or public PEM) that never signs: the incoming key before a rotation, or the retiring key after it |
172172

173173
See [AWS credentials](/integrations/aws-credentials#self-hosted-deployments) for setup and the rotation steps.

‎apps/sim/lib/credentials/token-service-accounts/descriptors.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1587,7 +1587,7 @@ export const TOKEN_SERVICE_ACCOUNT_DESCRIPTORS: Record<
15871587
],
15881588
docsUrl: 'https://docs.sim.ai/integrations/grain',
15891589
helpText:
1590-
'Create a personal access token in Grain under Settings > Integrations > API. It has the same access you have in Grain.',
1590+
'Create a personal or workspace access token in Grain under Settings > Integrations > API. A personal token has the same access you have in Grain.',
15911591
},
15921592
[GRANOLA_SERVICE_ACCOUNT_PROVIDER_ID]: {
15931593
providerId: GRANOLA_SERVICE_ACCOUNT_PROVIDER_ID,
@@ -1629,7 +1629,7 @@ export const TOKEN_SERVICE_ACCOUNT_DESCRIPTORS: Record<
16291629
],
16301630
docsUrl: 'https://docs.sim.ai/integrations/pagerduty',
16311631
helpText:
1632-
'An account administrator creates REST API keys in PagerDuty under Integrations > API Access Keys. Creating, updating, snoozing, merging, and noting incidents needs a full-access key; a read-only key covers the list and get operations.',
1632+
'Use an account REST API key (an administrator creates it under Integrations > API Access Keys) or a personal user API token (User Settings > API Access). Creating, updating, snoozing, merging, and noting incidents needs a full-access key; a read-only key covers the list and get operations.',
16331633
},
16341634
[RESEND_SERVICE_ACCOUNT_PROVIDER_ID]: {
16351635
providerId: RESEND_SERVICE_ACCOUNT_PROVIDER_ID,

‎apps/sim/lib/credentials/token-service-accounts/validators/gitlab.test.ts‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,11 @@ describe('GitLab saved token verification', () => {
5151
).rejects.toMatchObject({ code: 'invalid_credentials' })
5252
})
5353

54-
it('reports a malformed token lookup as GitLab misbehaving, not as a bad token', async () => {
55-
fetch.mockResolvedValue(new Response('<html>', { status: 200 }))
54+
it.each([
55+
['an HTML page', new Response('<html>', { status: 200 })],
56+
['JSON that is not a token lookup', jsonResponse({ ok: true })],
57+
])('reports %s as GitLab misbehaving, not as a bad token', async (_, reply) => {
58+
fetch.mockResolvedValue(reply)
5659

5760
await expect(
5861
validateGitLabServiceAccount({ apiToken: 'glpat-x', domain: 'gitlab.com' })

‎apps/sim/lib/credentials/token-service-accounts/validators/gitlab.ts‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,12 @@ export async function validateGitLabServiceAccount(
7272
})
7373
}
7474
const token = toRecord(body)
75+
if (typeof token.active !== 'boolean' || !Array.isArray(token.scopes)) {
76+
throw new TokenServiceAccountValidationError('provider_unavailable', 502, {
77+
step: 'verify',
78+
reason: 'GitLab returned an unexpected token lookup',
79+
})
80+
}
7581
const scopes = toArray(token.scopes)
7682
if (
7783
token.active !== true ||

‎apps/sim/lib/credentials/token-service-accounts/validators/token-checks.ts‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -407,9 +407,13 @@ export const validateGrainServiceAccount = tokenCheckValidator({
407407
}),
408408
})
409409

410-
/** Listing one Granola note answers 200 for a valid personal or workspace API key and 401 otherwise. */
410+
/**
411+
* Listing one Granola note answers 200 for a valid personal or workspace API key and 401 otherwise.
412+
* An Enterprise admin can turn off note scopes for members, so a JSON 403 still proves the key.
413+
*/
411414
export const validateGranolaServiceAccount = tokenCheckValidator({
412415
serviceLabel: 'Granola',
416+
forbiddenMeansScoped: true,
413417
request: ({ apiToken }) => ({
414418
url: `${GRANOLA_API_BASE}/notes?page_size=1`,
415419
headers: { ...granolaHeaders(apiToken), Accept: 'application/json' },

‎apps/sim/lib/credentials/workload-identity/issuer.test.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ describe('workload identity issuer', () => {
106106
'http://sim.example.com/oidc/workload',
107107
'https://sim.example.com:3000/oidc/workload',
108108
'https://sim.example.com/oidc/workload?tenant=1',
109+
'https://sim.example.com/oidc/workload#keys',
109110
])('stays off for an issuer no cloud can fetch (%s)', async (url) => {
110111
setEnv('WORKLOAD_IDENTITY_ISSUER', url)
111112
const issuer = await loadIssuer()

‎packages/deployment-config/src/integrations.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25244,7 +25244,7 @@
2524425244
"category": "tools",
2524525245
"integrationType": "analytics",
2524625246
"tags": ["seo", "marketing", "data-analytics"],
25247-
"updatedAt": "2026-11-10"
25247+
"updatedAt": "2026-10-14"
2524825248
},
2524925249
{
2525025250
"type": "sendblue",

0 commit comments

Comments
 (0)