diff --git a/backend/src/ee/routes/v1/secret-scanning-router.ts b/backend/src/ee/routes/v1/secret-scanning-router.ts index f144a6c00..1bc8e3998 100644 --- a/backend/src/ee/routes/v1/secret-scanning-router.ts +++ b/backend/src/ee/routes/v1/secret-scanning-router.ts @@ -1,11 +1,11 @@ import { z } from "zod"; import { GitAppOrgSchema, SecretScanningGitRisksSchema } from "@app/db/schemas"; +import { canUseSecretScanning } from "@app/ee/services/secret-scanning/secret-scanning-fns"; import { SecretScanningResolvedStatus, SecretScanningRiskStatus } from "@app/ee/services/secret-scanning/secret-scanning-types"; -import { getConfig } from "@app/lib/config/env"; import { BadRequestError } from "@app/lib/errors"; import { OrderByDirection } from "@app/lib/types"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; @@ -23,14 +23,14 @@ export const registerSecretScanningRouter = async (server: FastifyZodProvider) = body: z.object({ organizationId: z.string().trim() }), response: { 200: z.object({ - sessionId: z.string() + sessionId: z.string(), + gitAppSlug: z.string() }) } }, onRequest: verifyAuth([AuthMode.JWT]), handler: async (req) => { - const appCfg = getConfig(); - if (!appCfg.SECRET_SCANNING_ORG_WHITELIST?.includes(req.auth.orgId)) { + if (!canUseSecretScanning(req.auth.orgId)) { throw new BadRequestError({ message: "Secret scanning is temporarily unavailable." }); diff --git a/backend/src/ee/services/secret-scanning/secret-scanning-fns.ts b/backend/src/ee/services/secret-scanning/secret-scanning-fns.ts new file mode 100644 index 000000000..b1e2e0bbb --- /dev/null +++ b/backend/src/ee/services/secret-scanning/secret-scanning-fns.ts @@ -0,0 +1,11 @@ +import { getConfig } from "@app/lib/config/env"; + +export const canUseSecretScanning = (orgId: string) => { + const appCfg = getConfig(); + + if (!appCfg.isCloud) { + return true; + } + + return appCfg.SECRET_SCANNING_ORG_WHITELIST?.includes(orgId); +}; diff --git a/backend/src/ee/services/secret-scanning/secret-scanning-service.ts b/backend/src/ee/services/secret-scanning/secret-scanning-service.ts index c5e7be9d8..7d41091fc 100644 --- a/backend/src/ee/services/secret-scanning/secret-scanning-service.ts +++ b/backend/src/ee/services/secret-scanning/secret-scanning-service.ts @@ -12,6 +12,7 @@ import { NotFoundError } from "@app/lib/errors"; import { TGitAppDALFactory } from "./git-app-dal"; import { TGitAppInstallSessionDALFactory } from "./git-app-install-session-dal"; import { TSecretScanningDALFactory } from "./secret-scanning-dal"; +import { canUseSecretScanning } from "./secret-scanning-fns"; import { TSecretScanningQueueFactory } from "./secret-scanning-queue"; import { SecretScanningRiskStatus, @@ -47,12 +48,14 @@ export const secretScanningServiceFactory = ({ actorAuthMethod, actorOrgId }: TInstallAppSessionDTO) => { + const appCfg = getConfig(); + const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId); ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.SecretScanning); const sessionId = crypto.randomBytes(16).toString("hex"); await gitAppInstallSessionDAL.upsert({ orgId, sessionId, userId: actorId }); - return { sessionId }; + return { sessionId, gitAppSlug: appCfg.SECRET_SCANNING_GIT_APP_SLUG }; }; const linkInstallationToOrg = async ({ @@ -91,7 +94,8 @@ export const secretScanningServiceFactory = ({ const { data: { repositories } } = await octokit.apps.listReposAccessibleToInstallation(); - if (appCfg.SECRET_SCANNING_ORG_WHITELIST?.includes(actorOrgId)) { + + if (canUseSecretScanning(actorOrgId)) { await Promise.all( repositories.map(({ id, full_name }) => secretScanningQueue.startFullRepoScan({ @@ -102,6 +106,7 @@ export const secretScanningServiceFactory = ({ ) ); } + return { installatedApp }; }; @@ -164,7 +169,6 @@ export const secretScanningServiceFactory = ({ }; const handleRepoPushEvent = async (payload: WebhookEventMap["push"]) => { - const appCfg = getConfig(); const { commits, repository, installation, pusher } = payload; if (!commits || !repository || !installation || !pusher) { return; @@ -175,7 +179,7 @@ export const secretScanningServiceFactory = ({ }); if (!installationLink) return; - if (appCfg.SECRET_SCANNING_ORG_WHITELIST?.includes(installationLink.orgId)) { + if (canUseSecretScanning(installationLink.orgId)) { await secretScanningQueue.startPushEventScan({ commits, pusher: { name: pusher.name, email: pusher.email }, diff --git a/backend/src/lib/config/env.ts b/backend/src/lib/config/env.ts index 907884433..e38dbcfb5 100644 --- a/backend/src/lib/config/env.ts +++ b/backend/src/lib/config/env.ts @@ -146,6 +146,7 @@ const envSchema = z SECRET_SCANNING_GIT_APP_ID: zpStr(z.string().optional()), SECRET_SCANNING_PRIVATE_KEY: zpStr(z.string().optional()), SECRET_SCANNING_ORG_WHITELIST: zpStr(z.string().optional()), + SECRET_SCANNING_GIT_APP_SLUG: zpStr(z.string().default("infisical-radar")), // LICENSE LICENSE_SERVER_URL: zpStr(z.string().optional().default("https://portal.infisical.com")), LICENSE_SERVER_KEY: zpStr(z.string().optional()), diff --git a/docs/documentation/platform/secret-scanning.mdx b/docs/documentation/platform/secret-scanning.mdx index 4f030e882..da28bfa55 100644 --- a/docs/documentation/platform/secret-scanning.mdx +++ b/docs/documentation/platform/secret-scanning.mdx @@ -7,6 +7,113 @@ The Infisical Secret Scanner allows you to keep an overview and stay alert of ex To further enhance security, we recommend you also use our [CLI Secret Scanner](/cli/scanning-overview#automatically-scan-changes-before-you-commit) to scan for exposed secrets prior to pushing your changes. + + + + To setup secret scanning on your own instance of Infisical, you can follow the steps below. + + + + Create a new GitHub app in your GitHub organization or personal [Developer Settings](https://github.com/settings/apps). + + ![Create GitHub App](/images/platform/secret-scanning/github-create-app.png) + + ### Configure the GitHub App + To configure the GitHub app to work with Infisical, you'll need to modify the following settings: + - **Homepage URL**: Required to be set. Set it to the URL of your Infisical instance. (e.g. `https://app.infisical.com`) + - **Setup URL**: Set this to `https:///organization/secret-scanning` + - **Webhook URL**: Set this to `https:///api/v1/secret-scanning/webhook` + - **Webhook Secret**: Set this to a random string. This is used to verify the webhook request from Infisical. Use `openssl rand -base64 32` in your terminal to generate a random secret. + + + Remember to save the webhook secret as you will need it in the next step. + + + ![GitHub App Settings](/images/platform/secret-scanning/github-configure-app.png) + + ### Configure the GitHub App Permissions + The GitHub app needs the following permissions: + + Repository permissions: + - `Checks`: Read and Write + - `Contents`: Read-only + - `Issues`: Read and Write + - `Pull Requests`: Read and Write + - `Metadata`: Read-only (enabled by default) + + ![Github App Repository Permissions](/images/platform/secret-scanning/github-repo-permissions.png) + + Subscribed events: + - `Check run` + - `Pull request` + - `Push` + + ![Github App Subscribed Events](/images/platform/secret-scanning/github-subscribed-events.png) + + + ### Create the GitHub App + Now you can create the GitHub app by clicking on the "Create GitHub App" button. + + + If you want other Github users to be able to install the app, you need to tick the "Any account" option under "Where can this GitHub App be installed?" + + + ![Create GitHub App](/images/platform/secret-scanning/github-create-app-button.png) + + + + After clicking the "Create GitHub App" button, you will be redirected to the GitHub settings page. Here you can copy the "App ID" and save it for later when you need to configure your environment variables for your Infisical instance. + + ![Github App ID](/images/platform/secret-scanning/github-app-copy-app-id.png) + + + + The GitHub App slug is the name of the app you created in a slug friendly format. You can find the slug in the URL of the app you created. + + ![Github App Slug](/images/platform/secret-scanning/github-app-copy-slug.png) + + + + Create a new app private key by clicking on the "Generate a private key" button under the "Private keys" section. + + Once you click the "Generate a private key" button, the private key will be downloaded to your computer. Save this file for later as you will need the private key when configuring Infisical. + + ![Github App Private Key](/images/platform/secret-scanning/github-app-create-private-key.png) + + + Remember to save the private key as you will need it in the next step. + + + + + + + Now you can configure your Infisical instance by setting the following environment variables: + + - `SECRET_SCANNING_GIT_APP_ID`: The App ID of your GitHub App. + - `SECRET_SCANNING_GIT_APP_SLUG`: The slug of your GitHub App. + - `SECRET_SCANNING_PRIVATE_KEY`: The private key of your GitHub App that you created in a previous step. + - `SECRET_SCANNING_WEBHOOK_SECRET`: The webhook secret of your GitHub App that you created in a previous step. + + + + After restarting your Infisical instance, you should be able to use the secret scanning feature within your organization. Follow the steps below to add the GitHub App to your Infisical organization. + + +## Install the Infisical Radar GitHub App + +To install the GitHub App, press the "Integrate With GitHub" button in the top right corner of your Infisical Secret Scanning dashboard. + +![Integrate With GitHub](/images/platform/secret-scanning/infisical-connect-secret-scanner.png) + +Next, you'll be prompted to select which organization you'd like to install the app into. Select the organization you'd like to install the app into by clicking the organization in the menu. + +![Select Organization](/images/platform/secret-scanning/github-select-org-2.png) + +Select the repositories you'd like to scan for secrets and press the "Install" button. + +![Select Repositories](/images/platform/secret-scanning/github-select-repos.png) + ## Code Scanning ![Scanning Overview](/images/platform/secret-scanning/overview.png) diff --git a/docs/images/platform/secret-scanning/github-app-copy-app-id.png b/docs/images/platform/secret-scanning/github-app-copy-app-id.png new file mode 100644 index 000000000..a94cb5ece Binary files /dev/null and b/docs/images/platform/secret-scanning/github-app-copy-app-id.png differ diff --git a/docs/images/platform/secret-scanning/github-app-copy-slug.png b/docs/images/platform/secret-scanning/github-app-copy-slug.png new file mode 100644 index 000000000..c555dcd41 Binary files /dev/null and b/docs/images/platform/secret-scanning/github-app-copy-slug.png differ diff --git a/docs/images/platform/secret-scanning/github-app-create-private-key.png b/docs/images/platform/secret-scanning/github-app-create-private-key.png new file mode 100644 index 000000000..50f602a36 Binary files /dev/null and b/docs/images/platform/secret-scanning/github-app-create-private-key.png differ diff --git a/docs/images/platform/secret-scanning/github-configure-app.png b/docs/images/platform/secret-scanning/github-configure-app.png new file mode 100644 index 000000000..df64eeb18 Binary files /dev/null and b/docs/images/platform/secret-scanning/github-configure-app.png differ diff --git a/docs/images/platform/secret-scanning/github-create-app-button.png b/docs/images/platform/secret-scanning/github-create-app-button.png new file mode 100644 index 000000000..3ea4b2d38 Binary files /dev/null and b/docs/images/platform/secret-scanning/github-create-app-button.png differ diff --git a/docs/images/platform/secret-scanning/github-create-app.png b/docs/images/platform/secret-scanning/github-create-app.png new file mode 100644 index 000000000..f4d1cdb8c Binary files /dev/null and b/docs/images/platform/secret-scanning/github-create-app.png differ diff --git a/docs/images/platform/secret-scanning/github-register-app.png b/docs/images/platform/secret-scanning/github-register-app.png new file mode 100644 index 000000000..904c07bf2 Binary files /dev/null and b/docs/images/platform/secret-scanning/github-register-app.png differ diff --git a/docs/images/platform/secret-scanning/github-repo-permissions.png b/docs/images/platform/secret-scanning/github-repo-permissions.png new file mode 100644 index 000000000..53eae9a41 Binary files /dev/null and b/docs/images/platform/secret-scanning/github-repo-permissions.png differ diff --git a/docs/images/platform/secret-scanning/github-select-org-2.png b/docs/images/platform/secret-scanning/github-select-org-2.png new file mode 100644 index 000000000..55b945c18 Binary files /dev/null and b/docs/images/platform/secret-scanning/github-select-org-2.png differ diff --git a/docs/images/platform/secret-scanning/github-select-org.png b/docs/images/platform/secret-scanning/github-select-org.png new file mode 100644 index 000000000..7d6e5abc5 Binary files /dev/null and b/docs/images/platform/secret-scanning/github-select-org.png differ diff --git a/docs/images/platform/secret-scanning/github-select-repos.png b/docs/images/platform/secret-scanning/github-select-repos.png new file mode 100644 index 000000000..51a6648d2 Binary files /dev/null and b/docs/images/platform/secret-scanning/github-select-repos.png differ diff --git a/docs/images/platform/secret-scanning/github-subscribed-events.png b/docs/images/platform/secret-scanning/github-subscribed-events.png new file mode 100644 index 000000000..7aa6b431f Binary files /dev/null and b/docs/images/platform/secret-scanning/github-subscribed-events.png differ diff --git a/docs/images/platform/secret-scanning/infisical-connect-secret-scanner.png b/docs/images/platform/secret-scanning/infisical-connect-secret-scanner.png new file mode 100644 index 000000000..11f24fd74 Binary files /dev/null and b/docs/images/platform/secret-scanning/infisical-connect-secret-scanner.png differ diff --git a/docs/internals/bug-bounty.mdx b/docs/internals/bug-bounty.mdx index b823e6246..e45de05bf 100644 --- a/docs/internals/bug-bounty.mdx +++ b/docs/internals/bug-bounty.mdx @@ -41,7 +41,7 @@ All final reward amounts are determined at Infisical's discretion based on impac ### Out of Scope -- Social engineering or phishing +- Social engineering or phishing (including email hyperlink injection without code execution) - Rate limiting issues on non-sensitive endpoints - Denial-of-service attacks that require authentication and don't impact core service availability - Findings based on outdated or forked code not maintained by the Infisical team @@ -57,4 +57,24 @@ We ask that researchers: - Use testing accounts where possible - Give us a reasonable window to investigate and patch before going public -Researchers can also spin up our [self-hosted version of Infisical](/self-hosting/overview) to test for vulnerabilities locally. \ No newline at end of file +Researchers can also spin up our [self-hosted version of Infisical](/self-hosting/overview) to test for vulnerabilities locally. + +### Program Conduct and Enforcement + +We value professional and collaborative interaction with security researchers. To maintain the integrity of our bug bounty program, we expect all participants to adhere to the following guidelines: + +- Maintain professional communication in all interactions +- Do not threaten public disclosure of vulnerabilities before we've had reasonable time to investigate and address the issue +- Do not attempt to extort or coerce compensation through threats +- Follow the responsible disclosure process outlined in this document +- Do not use automated scanning tools without prior permission + +Violations of these guidelines may result in: + +1. **Warning**: For minor violations, we may issue a warning explaining the violation and requesting compliance with program guidelines. +2. **Temporary Ban**: Repeated minor violations or more serious violations may result in a temporary suspension from the program. +3. **Permanent Ban**: Severe violations such as threats, extortion attempts, or unauthorized public disclosure will result in permanent removal from the Infisical Bug Bounty Program. + +We reserve the right to reject reports, withhold bounties, and remove participants from the program at our discretion for conduct that undermines the collaborative spirit of security research. + +Infisical is committed to working respectfully with security researchers who follow these guidelines, and we strive to recognize and reward valuable contributions that help protect our platform and users. diff --git a/docs/self-hosting/configuration/envars.mdx b/docs/self-hosting/configuration/envars.mdx index d9eef9cb0..b63c58d3a 100644 --- a/docs/self-hosting/configuration/envars.mdx +++ b/docs/self-hosting/configuration/envars.mdx @@ -29,6 +29,19 @@ Used to configure platform-specific security and operational settings Specifies the internal port on which the application listens. + + Specifies the network interface Infisical will bind to when accepting incoming connections. + + By default, Infisical binds to `localhost`, which restricts access to connections from the same machine. + + To make the application accessible externally (e.g., for self-hosted deployments), set this to `0.0.0.0`, which tells the server to listen on all network interfaces. + + Example values: + - `localhost` (default, same as `127.0.0.1`) + - `0.0.0.0` (all interfaces, accessible externally) + - `192.168.1.100` (specific interface IP) + + Telemetry helps us improve Infisical but if you want to disable it you may set this to `false`. @@ -612,6 +625,26 @@ To help you sync secrets from Infisical to services such as Github and Gitlab, I +## Secret Scanning + + + + The App ID of your GitHub App. + + + + The slug of your GitHub App. + + + + A private key for your GitHub App. + + + + The webhook secret of your GitHub App. + + + ## Observability You can configure Infisical to collect and expose telemetry data for analytics and monitoring. diff --git a/frontend/src/hooks/api/secretScanning/mutation.ts b/frontend/src/hooks/api/secretScanning/mutation.ts index 7298b9af1..5055da4aa 100644 --- a/frontend/src/hooks/api/secretScanning/mutation.ts +++ b/frontend/src/hooks/api/secretScanning/mutation.ts @@ -10,15 +10,17 @@ import { } from "./types"; export const useCreateNewInstallationSession = () => { - return useMutation<{ sessionId: string }, object, { organizationId: string }>({ - mutationFn: async (opt) => { - const { data } = await apiRequest.post( - "/api/v1/secret-scanning/create-installation-session/organization", - opt - ); - return data; + return useMutation<{ sessionId: string; gitAppSlug: string }, object, { organizationId: string }>( + { + mutationFn: async (opt) => { + const { data } = await apiRequest.post( + "/api/v1/secret-scanning/create-installation-session/organization", + opt + ); + return data; + } } - }); + ); }; export const useUpdateRiskStatus = () => { diff --git a/frontend/src/pages/organization/SecretScanningPage/SecretScanningPage.tsx b/frontend/src/pages/organization/SecretScanningPage/SecretScanningPage.tsx index ba919cdd3..23cdcf800 100644 --- a/frontend/src/pages/organization/SecretScanningPage/SecretScanningPage.tsx +++ b/frontend/src/pages/organization/SecretScanningPage/SecretScanningPage.tsx @@ -108,7 +108,7 @@ export const SecretScanningPage = withPermission( const generateNewIntegrationSession = async () => { const session = await createNewIntegrationSession({ organizationId }); - window.location.href = `https://github.com/apps/infisical-radar/installations/new?state=${session.sessionId}`; + window.location.href = `https://github.com/apps/${session.gitAppSlug}/installations/new?state=${session.sessionId}`; }; return (