Security guidelines
Periodical Maintenance Tasks
Taking care of an application’s security is not a one-off task, but an ongoing effort. Here is a reference of some tasks you should perform periodically (every few months) to ensure the application is not only built in a secure way but also kept always secure.
Search the code for secrets
Make sure no credentials have been introduced to the code. There are static analysis tools that can help detect leaked secrets. trufflehog is one such tool. It can be used in a Github Action, ran as a git commit hook, or just run manually from the command line.
Search vulnerabilities
There are static analysis tools to automatically detect CVEs and other vulnerabilities in an application or built artifact.
Snyk is one such tool. It is cross-platform and allows detecting vulnerabilities in several language runtimes, in Docker images, Infrastructure-as-Code definitions, and Open Source dependencies.
We will also check the dependency scanner built in GitHub. Check the Dependant bot quickstart guide on further details on how to configure it in your repository.
There are other platform-specific solutions that can also be very useful and complete the more generic scans.
Rails
- Brakeman can scan for several vulnerabilities on Rails projects. It can be used in a Github Action to run on every pull request, run as a git commit hook, or run manually on the demand from the command line.
- Bundler-audit can find vulnerable library versions and provide an upgrade path to a secure version.
- Ruby version check: Ensure the apps run on a supported Ruby version.
Next.js
- Enable dependency and runtime scanning in CI:
npm audit/yarn npm auditfor quick checks.- Dependabot to monitor npm vulnerabilities and open upgrade PRs.
- Add static checks and secure config verifications:
- Verify
next.config.jshas strict security headers (HSTS,X-Content-Type-Options,X-Frame-Options,Referrer-Policy) and a CSP policy. - Validate
images.remotePatternsis restricted to known hosts; avoid overly broad wildcards. - If using SVGs, confirm
dangerouslyAllowSVGis truly needed and CSP for images is restrictive.
- Verify
- Lint for dangerous patterns:
- Disallow
dangerouslySetInnerHTMLwithout sanitization. - Flag dynamic
child_processusage andrequire()with untrusted values in server code.
- Disallow
- Review authentication and session setup regularly:
- Ensure cookies are
HttpOnly,Secure,SameSite=Laxand rotated on login. - For Server Actions, set
serverActions.allowedOriginswhen behind proxies and keepNEXT_SERVER_ACTIONS_ENCRYPTION_KEYconfigured in self-hosted setups.
- Ensure cookies are
- Ensure that the application runs on a supported Node version.
- Tools or lint rules should flag:
- Any usage of dangerouslySetInnerHTML without sanitization:
- eslint-plugin-react has react/no-danger
- Dynamic calls to child_process:
- eslint-plugin-security has security/detect-child-process
- Dynamic require() using untrusted data
- eslint-plugin-import has import/no-dynamic-require
- Any usage of dangerouslySetInnerHTML without sanitization:
Docker
- Docker scout can be used to detect CVEs in all the layers of a Docker image.
- docker scan or platform-provided scanners
- Snyk container scanning
- Make sure the containers are built on top of OS images that are still supported and receiving security upgrades.
Remove obsolete 3rd party integrations
It is important to revoke access to the code/data from an integration once it is no longer used. These may be:
- Error tracking tools (example: Sentry).
- Performance monitoring tools (example: New Relic, DataDog).
- User analytics tools (example: Google Analytics, Mixpanel).
- Code analysis tools (example: Code Climate).
- Continuous Integration tools (example: Circle CI).
- Project management tools (example: Linear).
- Repositories.
Once such a tool is no longer needed we should make sure to:
- Revoke API keys and/or users from the service.
- Remove the corresponding environment variables and - secrets if necessary.
- Remove libraries from the code, if necessary.
- Remove running processes, if necessary.
Remove public access from S3 buckets
We often use AWS S3 to store files uploaded to a web application. We should make sure that these buckets have public access disabled and only allow public access when strictly necessary and only for files that don’t contain any confidential or sensitive information. When creating a new bucket, public access is disabled by default. Nevertheless, it’s a good idea to check all existing buckets to make sure their configuration is correct, in case it has been changed.
When downloading files from S3, in general, we should do it from the back end. When doing so, no public access is needed because the back end will download the file from S3 using an authorization token.
ℹ️ Public access is only needed if we want users to download those files from an S3 URL directly without going through the server.
Review users and permissions
Make sure that only people working currently on the project has access to 3rd party services. Remove any user that does not correspond to any of these people. These include:
- Remote repository (example: Github).
- Error tracking tools (example: Sentry)
- Monitoring tools (example: New Relic, DataDog).
- Analytics tools (example: Google Analytics, Mixpanel).
- Code analysis tools (example: Code Climate).
- Continuous Integration tools (example: Circle CI).
- Project management tools (example: Linear).
- Cloud provider (examples: AWS, Digital Ocean, Azure).
- Web application on production and pre-production environments.
Other key places to check:
- VPN: Revoke any unneeded VPN users or certificates.
- SSH keys: Remove any unneeded SSH keys from remote servers.
- 1password vault.
Cloud provider
⚠️ The cloud provider deserves special attention because it allows direct access to the application infrastructure. Apart from making sure only people working on the project have access, we should review their permissions.
The majority of cloud providers have an IAM system that allows giving very specific permissions to each user. Make sure that each user has only the strictly necessary permissions to perform their work. This adds security to the project and peace of mind to the team members. For example:
- There should be just one or two admin users with complete control of the account.
- The tech lead should have complete permissions over all the services used by the application, and IAM permissions to be able to configure and modify users. But she should not have permission for billing, or services not used by the application.
- Most software engineers should have only the necessary permissions to deploy, view the deployment service (EKS, ECS, etc.), and view the logs.
⚠️ Another key point is adding only the strictly necessary permissions to users corresponding to the web application or 3rd party services.
Often an application will need to interact with the cloud provider. The most common example is when uploading files to an S3 bucket. Use policies with granular permissions to allow access only to the exact services and resources needed by the application. For example, if the application needs to upload files to S3 we would add a policy to the user with only the 3 or 4 permissions to upload and download files and limit those to only the bucket that has the files.
Web application on production and pre-production environments
Make sure only people working on the project have access to the application (in any of its environments). This usually translates into checking the admin users on the application, but it may be other types of user accounts or access methods.
Logging, Monitoring & Alerts
Check that:
- Sensitive data is filtered from logs:
- passwords, tokens, credit cards, secrets
- Alerts exist for:
- login failures
- unusual traffic patterns
- spikes in 4xx/5xx errors
- Logs are retained securely and access is controlled
- Audit logs (if present) are reviewed periodically
Dependency & Runtime Updates (All Stacks)
Make sure:
- Base images updated (for Docker)
- Frameworks updated (Rails, Next.js)
- Libraries and runtime dependencies upgraded
- EOL/runtime versions are not in use
- CI/CD pipeline has the latest scanning tools enabled