Files
servicedesk/SECURITY.md
Kacper 90fae0a4de v1.1.0
- In-app notifications: a bell in the top bar backed by Laravel's database
  notification channel, alongside existing e-mail notifications (same
  per-trigger toggle drives both; ticket links now correctly point into the
  recipient's own area instead of always linking to the client view).
- Drag-and-drop attachments on every upload form, plus inline image
  thumbnails in the message thread instead of a plain download link.
- Customer satisfaction (CSAT) rating: clients rate a closed ticket 1-5 stars
  with an optional comment; shown read-only to operators, surfaced as a KPI
  on the stats dashboard, and linked from the "ticket closed" e-mail.
- Saved queue views: operators can save/apply/delete named filter+sort+
  column presets in the ticket queue and mark one as their default.
- Full-text search (MySQL FULLTEXT, portable LIKE fallback) across ticket
  subject/body and reply message bodies, now also on the client's own ticket
  list.
- Stats CSV export for the currently filtered ticket set.
- Optional BookStack knowledge-base integration (off by default): suggests
  articles by category/subcategory while creating a ticket and in a separate
  sidebar for operators on an existing ticket (with a copy-link button).
  Configurable connection/SSL bypass/search-type filter, plus two
  independent per-shelf allow-lists so nothing is ever searched until an
  admin opts specific shelves in.
- Closed tickets no longer show in "Moje zgłoszenia"/"Nieprzypisane"/team
  queue tabs, only under "Zamknięte" (matching how "Otwarte" already worked).
- Wired up the Admin > About "Wersja" field to config('app.version')/VERSION
  in .env instead of a stale hardcoded string.
- Fixed: TicketService::setStatus() now checks a status's stage rather than
  the literal key 'closed' to decide whether to fire the "ticket closed"
  notification/stop the timer.
- Updated README/ARCHITECTURE/CHANGELOG/install/SECURITY docs and all three
  wiki/ role guides for the above; documented a root-vs-www-data file
  ownership gotcha in CLAUDE.md (running artisan commands via a plain
  `docker exec` can leave root-owned Blade cache files that later break
  recompilation for the www-data Apache process).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-22 15:18:09 +02:00

65 lines
3.5 KiB
Markdown

# Security Policy
This is an internally-run production helpdesk (not an open-source project with a
public disclosure program). If you find a vulnerability affecting this
deployment, report it directly rather than opening a public GitHub issue:
- **Contact**: the address configured as `AUTHOR_CONTACT` in `src/.env`
(surfaced in the app under Admin > O aplikacji).
- Please include steps to reproduce and, if applicable, which role/area
(Client/Operator/Admin/API) is affected.
Do not test against the production instance beyond what's needed to demonstrate
the issue — no automated scanning, load testing, or bulk data extraction.
## Scope & sensitive data
This system holds real ticket content, user PII (names/emails, and anything
submitted in ticket bodies/custom fields), and LDAP/SMTP connection credentials.
Treat access to the `admin` area, the `settings` table, and any `.env` file as
credential-equivalent.
## Notable design points relevant to security review
- **Auth**: LDAP bind is the primary login path (`config/auth.php`,
`directorytree/ldaprecord-laravel`); a local fallback account
(`admin@example.com`, seeded — **must** have its password changed after
install, see [install.md](install.md)) exists for when LDAP is unavailable or
misconfigured.
- **Settings override**: Admin > Konfiguracja values in the `settings` table
override `.env` for LDAP/SMTP/session/timezone config at runtime (see
[ARCHITECTURE.md](ARCHITECTURE.md) — "Settings override"). This means a
compromised admin account can redirect LDAP/SMTP traffic without touching the
filesystem — restrict Admin-role accounts accordingly.
- **API**: Sanctum tokens are ability-scoped (`tickets:read`, `tickets:write`,
`dictionaries:read`, `users:read`) and issued per `ApiClient` via the admin
panel; rate-limited per-client (authenticated) or per-IP (unauthenticated) —
see `AppServiceProvider::configureApiRateLimiting()`.
- **Role model**: roles are checked via `EnsureRole` middleware against
`$user->roles`; there's no per-object ACL beyond team-based ticket visibility
(`Ticket::scopeVisibleToOperator`) — any change to that scope directly changes
what an operator can see across teams.
- **Attachments**: size/count/type limits are admin-configurable
(`attachment_max_size_kb`, `attachment_allowed_types`, etc. in `Settings`) —
don't bypass them when adding new upload paths.
- **TLS**: production traffic terminates at Traefik with a private CA
certificate (not publicly trusted) — this is expected for this deployment, not
a misconfiguration.
- **BookStack integration** (`App\Services\BookStackClient`, optional, off by
default): the only outbound HTTP client in the codebase. The target
`bookstack_base_url` and the SSL-verification bypass (`bookstack_verify_ssl`)
are both admin-configurable — restrict Admin-role accounts accordingly, same
reasoning as the LDAP/SMTP settings override above (a compromised admin
account could point it at an arbitrary host, or disable TLS verification
against one). The API token secret is stored encrypted (same as the LDAP
bind/SMTP passwords). Nothing is ever searched/suggested until an admin
explicitly allow-lists specific BookStack shelves — the default (no shelves
allowed) returns no results without making any outbound request.
## Dependencies
No automated dependency-vulnerability scanning (e.g. Dependabot, `composer
audit` in CI) is currently configured — there is no CI pipeline for this repo at
all (see [TESTING.md](TESTING.md)). Run `composer audit` / `npm audit` manually
before major dependency bumps.