This document covers description and expected resolution of security vulnerability that can be encountered when writing code in the Tuleap codebase. The goal is to help developers identify security vulnerabilities early in the development process.
Contributions adding a new class of vulnerability or modifying the proposed mitigations are expected to be approved by a member of the Tuleap Security team.
Short answer: anywhere where user provided data is displayed (i.e. anywhere).
See OWASP Cross Site Scripting document.
For code generating the content on the backend side, use Mustache.
For code generating the content on the frontend side, you should also use a template engine. Depending on the situation it can be Vue, lit, hybrids or possibly mustache.js.
For situations where user provided HTML code needs to be displayed it needs to be sanitized first:
- when building the content on the backend side, use Codendi_HTMLPurifier
- when building the content on the frontend side, use DOMPurify. If you are
writing Vue code, use vue-dompurify-html which provides a directive
to replace
v-html
.
Issue can be encountered when writing SQL queries.
See OWAP SQL Injection document.
Follow the instructions given on backend database page.
Issue can be encountered when processing a request modifying a state on the server.
See OWASP Cross Site Request Forgery document.
Make sure that requests that are expected to change a server state can only be done with the appropriate HTTP verb
(POST
, PUT
, PATCH
or DELETE
) and not with an HTTP verb that is expected to be used only to query data
(GET
, OPTIONS
, HEAD
, CONNECT
or TRACE
).
When writing an HTML form, a CSRF synchronizer token is expected to be set and verified, See how to achieve that in the Mustache templating guide.
Issue can be encountered when creating and executing OS command containing data provided by a user.
See OWASP Command Injection document.
Overall, passing user-supplied data to OS commands should preferably be avoided. If it is not possible due to performance reasons or lack of alternatives:
- escape arguments: relying on the Symfony Process component
is the preferred way to achieve that,
escapeshellarg()
can be used if necessary - validate arguments against an allow list
- use
--
when possible to separate options from arguments
Issue can be encountered when doing an outbound HTTP request.
See OWASP Server-Side Request Forgery document.
Follow the instructions given on the Making HTTP requests page. Internal requests needs to be distinguished from requests made for users.
Everytime a new feature or endpoint is implemented.
See OWASP document about access-control and the Tuleap Permissions model.
It must be ensured that the Tuleap Permissions model is respected and, if not possible, amended to include to cover the change.
The general guidelines about the expected code must be followed (especially regarding tests) and reviewers must have a special point of vigilance.
Special care must be taken when manipulating secrets/credentials to limit the possibility of leaking them.
Are considered secrets/sensitive information:
- login information such as a username/password
- Access keys and tokens (personal access keys, OAuth2 tokens…)
- Anything that can be used to authenticate or authorize accesses
Secrets stored in the database are expected to be:
- hashed in an appropriate manner when the need is only to compare it against another value
- passwords and user provided secrets must be hashed using a key derivation function designed for this use case, use
StandardPasswordHandler::computeHashPassword()
- for randomly generated keys like personal access keys use the "split token" pattern
- passwords and user provided secrets must be hashed using a key derivation function designed for this use case, use
- encrypted using
SymmetricCrypto::encrypt()
if accessing the plaintext value is required
- never log a secret
- use
ConcealedString
when manipulating a sensitive string to avoid leaking inadvertently in a stack trace and preventing it to be serialized - call
sodium_memzero()
once you have wrapped your sensitive string in aConcealedString
in order to try to limit its exposure as much as possible
- use an encrypted channel like TLS (e.g. HTTPS) when transmitting or receiving credentials
- secrets should preferably be sent in the request body instead of the URL parameters as it is less likely to be logged
Issue can be encountered when doing cryptographic operations such as encrypting, signing or hashing data.
See OWASP Top 10 2021 - Cryptographic failures.
- For encrypting data see the previous section "Handling secrets"
- The
Tuleap\Cryptography
namespace offers hard to misuse interfaces for some symmetric and asymmetric cryptography operations - If your need is not covered by the existing solutions please reach out to a team member experienced in applied
cryptography. The following APIs can be used to design a solution solving your problem:
hash()
with SHA-256, SHA-384, SHA-512, SHA-512/256hash_hmac()
with SHA-256, SHA-384, SHA-512, SHA-512/256sodium_*
functions