5.5 KiB
Threat model
What this project does
solidtime is an open-source, multi-tenant time tracking web application (Laravel backend, Vue 3 + Inertia frontend,
PostgreSQL). It runs as a hosted SaaS (solidtime.io) and is self-hosted by many organisations. Users belong to one or
more organizations; inside an organization each member has a role: owner, admin, manager, employee or
placeholder (an imported, non-login member). What each role may do is defined in app/Service/PermissionStore.php.
The most important security property is isolation: a user must never read or modify data of an organization they are not a member of, and within an organization a member must not exceed the permissions of their role (e.g. an employee must not see other members' time entries, billable rates, or manage members, unless the organization settings explicitly allow it).
Where untrusted input enters
All authenticated users, including employees of any organization and anyone who self-registers (registration is open by default), are untrusted.
- JSON API
routes/api.php(/api/v1/...), authenticated via Passport (session cookie or personal access token). Most routes are scoped by{organization}and authorised in the controllers / form requests. - Public, unauthenticated endpoints:
GET /api/v1/public/reports(shared reports, accessed by a secret), login, registration, password reset, email verification, organization invitation acceptance (routes/web.php). - Web / Inertia routes
routes/web.phpand Fortify/Jetstream actions inapp/Actions. - Imports (
app/Service/Import/Importers): user-uploaded CSV and ZIP files from Toggl, Clockify, Harvest, generic CSV and solidtime's own export format. ZIP handling is inZipImportHelper.php. - Exports / reports (
app/Service/Export,app/Service/ReportExport): CSV/XLSX/ODS and PDF. PDFs are rendered by sending HTML to a Gotenberg (headless Chromium) service, so user-controlled content in that HTML matters. - OAuth (Passport) authorization and token endpoints.
- Filament admin panel (
app/Filament), only for instance super admins (SUPER_ADMINSenv). Super admins are trusted.
Components that matter most / least
Most important: organization scoping and role checks in the API controllers, form requests (app/Http/Requests),
PermissionStore, public report sharing, invitations and member management (role changes, ownership transfer, member
merge), authentication flows (Fortify, 2FA, email change, API tokens), import parsing.
Less important / out of scope:
extensions/is empty in this repository (proprietary modules are not part of the open-source code).docker/,k8s/,e2e/,playwright/,docs/and developer tooling.- Third-party dependencies in
vendor/andnode_modules/, unless solidtime uses them in an unsafe way.
How to exercise it
.oss-scanner/start-postgres.shstarts the local PostgreSQL server (userroot, passwordroot, dblaravel).php artisan testruns the PHPUnit suite. Endpoint tests intests/Unit/Endpoint/Api/V1/show how to create users, organizations and members with factories and call the API with a given role; they are the quickest way to write a reproducer. Example:php artisan test --filter=TimeEntryEndpointTest.- To run the app:
php artisan migrate:fresh --seed && php artisan serve(http://127.0.0.1:8000). Note that the test suite and the app share the same database. - There is no network: Gotenberg (PDF generation) and mail delivery are not available. Mail uses the
arraydriver in tests. The 8 PDF export tests inTimeEntryEndpointTestfail for this reason; that is expected.
How we rate severity
- Critical: unauthenticated access to other users' data or accounts; authentication bypass; remote code execution; SQL injection reachable by any registered user; reading or writing data of an organization the attacker is not a member of.
- High: privilege escalation within an organization (e.g. employee to admin/owner, or performing admin-only actions); access to data the role must not see (other members' time entries, billable rates, member emails) when the organization settings do not allow it; stored XSS that executes in another user's session; SSRF via PDF rendering or imports; account takeover requiring user interaction.
- Medium: information disclosure with limited impact, CSRF on state-changing endpoints, issues requiring an unusual but realistic configuration, denial of service by a single authenticated request (e.g. pathological import file).
- Low: everything else with real security impact.
Anything to leave alone
Please do not report (see also SECURITY.md):
- Theoretical findings without a working reproducer.
- Missing or weak security headers in isolation; TLS / mail DNS configuration.
- Self-XSS; CSRF on non-state-changing endpoints (logout, theme).
- CSV / spreadsheet formula injection in exports.
- Owners or admins acting destructively within their own organization.
- Anything requiring direct DB, shell or filesystem access on a self-hosted instance, or super admin access.
- Missing OAuth scope enforcement (not implemented yet).
- Rate-limit tuning and generic DoS through volume of requests.
Reports and patches
Please include the affected endpoint or code path, the attacker's role and the victim, a PHPUnit test (in the style of
tests/Unit/Endpoint/Api/V1/) that reproduces the issue, and a minimal patch that follows the existing patterns
(authorisation in form requests/controllers via PermissionStore).