Skip to content

2.1.0

Choose a tag to compare

@horilla-opensource horilla-opensource released this 06 Sep 07:28
· 32 commits to 2.0 since this release
40c6e94

Horilla HR 2.1.0

This is a security release. We recommend everyone running 2.0.0 upgrade.

2.0.0 shipped on 30 August. Since then a full security and architecture review of the codebase
closed a number of access-control and injection issues, several of which are reachable without
authentication. If you run Horilla — self-hosted or otherwise — please upgrade.

⚠️ Breaking change: WhatsApp integration requires an App Secret

If you use the WhatsApp integration, message delivery stops until you set the Meta App
Secret
in the WhatsApp credentials screen (find it under App Settings → Basic in the Meta
developer console).

This is deliberate. The webhook previously accepted any payload that reached it, and every POST
is acted on as the employee whose phone number the payload names — creating leave, attendance,
shift, asset and reimbursement requests, and able to mail that employee's documents to the
sender. Anyone who knew an employee's phone number could forge all of it.

Incoming webhooks are now verified against Meta's X-Hub-Signature-256 header. With no App
Secret configured the payload is refused and the reason logged, because accepting unverified
payloads would leave the endpoint exactly as exposed as before.

No other integration is affected.

Security fixes

Access control:

  • Resumes were readable by anyone. The public job-application form accepted any resume id
    and attached that file to the submitted application. Ids are sequential, so this exposed every
    CV in the database, across all companies, with no login required. Resume access is now scoped
    to the recruitment it belongs to.
  • API writes are permission-checked. Around fifteen endpoints accepted any authenticated
    user's token for operations that should require a role: asset approvals and deletion,
    attendance validation, overtime approval, tax brackets, reimbursement approval, bulk shift
    deletion, and sending mail as the company.
  • Cross-employee data access closed. Bank details, contract and salary tabs, performance
    objectives, announcements and notifications could be read or modified by employees other than
    their owner.
  • Export column paths restricted. The quick-export feature accepted arbitrary attribute
    paths, including ones that reached password hashes and bank account numbers.
  • Default Export Access is now an explicit setting. It previously defaulted to "everyone can
    export" whenever no setting row existed, which meant a fresh install allowed every user to
    export employee, payroll and attendance data with nothing recording that choice.

Injection and disclosure:

  • Stored cross-site scripting in the helpdesk FAQ page, and user-authored rich text (ticket
    descriptions and comments, recruitment descriptions, policy bodies, performance comments) is
    now sanitised against an allow-list rather than rendered raw.
  • Server-side template injection in eleven mail-template render paths that could expose
    password hashes and personal data.
  • A sandbox escape in the payroll tax-formula evaluator.
  • The generated SECRET_KEY was downloadable by any logged-in user when running under
    Docker, allowing session and token forgery.
  • Login lockout could be bypassed by rotating a request header.
  • Onboarding portal tokens are no longer served through the API or embedded in log output.

Hardening:

  • Two-factor codes are compared in constant time and expire after five failed attempts.
  • API documentation is restricted to administrators outside debug mode.
  • Idle sessions expire after 12 hours; secure cookie defaults now follow the production flag.
  • The readiness endpoint no longer discloses database connection details.
  • API rate limiting added; tokens are revoked when a password changes.
  • 21 dependency CVEs cleared, the last one mitigated in application code.

Reliability

  • Payslip generation is now atomic, so a failure part-way cannot leave a payslip half-written.
  • Backup failures are no longer silent. A failed database dump previously uploaded whatever
    stale file was on disk and reported success.
  • Background email is sent after the transaction commits, fixing mail that referenced records
    that had not been saved yet.
  • Leave balance forecasting corrected; OKR progress calculation fixed.
  • Scheduled jobs run in a single process rather than once per worker, so payslip runs, shift
    rotation and backups no longer fire multiple times per interval.
  • Outbound integration calls now time out instead of hanging a worker indefinitely.
  • Date columns indexed on the tables most often filtered by them.

Improvements

  • Redesigned public career pages.
  • New filter panel across list views; independent per-tab navigation in performance, helpdesk
    and asset modules.
  • Kanban drag-and-drop consolidated onto the generic view layer.
  • Audit logging now covers payroll, leave and attendance by default.
  • JSON logging with request correlation ids; optional error reporting with personal data scrubbed.
  • Continuous integration now runs against PostgreSQL with dependency, secret and code scanning.

Upgrading

docker pull horilla/horilla-hr:2.1.0

Run migrations as usual. One data migration seeds the Default Export Access setting for existing
companies, preserving current behaviour.

If you use WhatsApp, set the App Secret before or immediately after upgrading — see the
breaking change above.