Skip to content

Papra changelog

Here are the changelogs of the docker images released by Papra.
For version after v0.9.6, Papra uses Calver as a versioning system with the format YY.M.N where M is the month number (1-12, not zero-padded, where 1 = January and 12 = December) and N is the number of releases in the month starting at 0 (e.g. 26.5.11 is the 12th release of May 2026).

v26.4.0

  • Breaking change regarding webhook URLs

    Added SSRF protection for webhook URLs. Webhook URLs are now validated to ensure they do not point to private or reserved IP addresses, preventing potential server-side request forgery attacks. So webhooks pointing to private IPs (e.g. http://192.168.0.1/some/stuff), or with domains resolving to private IPs (e.g. http://myservice.local/some/stuff) will be blocked unless explicitly allowed.

    Two new configuration options are available:

    • WEBHOOK_SSRF_PROTECTION_ENABLED Set to false to fully disable SSRF protection. This is not recommended, prefer using the allowlist below instead.
    • WEBHOOK_URL_ALLOWED_HOSTNAMES A comma-separated list of hostnames (IP addresses or domain names) that are explicitly trusted and exempt from SSRF checks (e.g. internal services you control).

    Addressing GHSA-cjw7-qg95-58mq, credit to @Toothless5143 for the responsible disclosure.

  • Removed currently unused expiresAt placeholder fields in the internal API key creation endpoint to avoid confusions, as non-ui (so non-standard) creation of API keys can set an expiration date, which is not currently enforced by the system.

    Addressing GHSA-866c-mc22-wvv5, credit to @Toothless5143 for the responsible disclosure.

  • Properly return a "document already has tag" error when trying to add a tag to a document that already has it, instead of a generic 500 error when using an hosted Turso db.

  • Api now returns a 409 status code instead of a 400 when either creating a tag that already exists or adding a tag to a document that already has it.

  • Properly sanitize user name before including it in the email content to prevent potential XSS or html injection attacks.

    Addressing GHSA-6f8x-2rc9-vgh4, credit to @Toothless5143 for the responsible disclosure.

  • Moved the theme picker to the user settings dropdown

  • App environment configuration validation is now a bit stricter, with slightly different error messages. And the following specific changes:

    • Boolean env variables previously considered non-truthy values as false. Now they will throw a validation error if the value is not a valid boolean-ish value
    • AUTH_PROVIDERS_CUSTOMS json parsing now accepts only valid boolean values for the pkce property, while before it accepted any non-true value as false
    • Stricter AUTH_FORBIDDEN_EMAIL_DOMAINS domain validation

v26.3.0

v26.2.2

v26.2.1

v26.2.0

  • Added a "Open with..." button for documents along with a complete PDF viewer page with standard features such as thumbnails, outline, attachments, and document properties.

  • Replaced date-fns functions with in-house implementations to avoid pulling the 30MB lib (mainly due to locale data).

  • Added explicit error when trying to update a tag with a name that already exists

  • In the search queries, tag filters are now case-insensitive, so tag:Important and tag:important will match the same tag (as tags names are case-insensitive).

  • Synchronized pagination state in the URL on the documents list page.

  • Trim tag names and descriptions on creation and update to avoid leading/trailing spaces.

  • Added a button to generate a random color in the tag creation/edition modal.

  • Significantly reduced the size of the rootless docker image by preventing file duplications due to chown operations, gaining ~230MB, more than 30% reduction in size.

  • Added an option to limit the number of tags that can be created in an organization, defaulting to 200. Configurable via the MAX_TAGS_PER_ORGANIZATION environment variable.

  • Excluded Synology specific files for the ingestion folder

  • Coerce MIME type of intake email attachments when declared as application/octet-stream or empty, using magic bytes detection with extension-based fallback.

  • Fixed a race condition that could incorrectly show the "Email verified" page after successful login, even when email verification had not been completed or was not required.

  • Improved the document tag picker UI and UX, allowing tags to be managed from the document list.

  • Added tagging rules creation/update loading states

  • Removed misleading "git missing" error log on app startup when git isn't available, like in Docker env.

  • Tag names uniqueness enforced with case insensitivity per organization. Migration will ensure deduplication by appending prefixes in case of existing collisions.

  • Added small header in organization creation page to quickly access the invitations when first organization is being created

  • The command palette state no longer resets when opening it, allowing to keep the search query and results when closing and reopening it.

  • Added tag creation/update button loading state

  • Enforced the length of the intake email webhook secret (INTAKE_EMAILS_WEBHOOK_SECRET) to be between 16 and 128 characters to match the OwlRelay API validation requirements.

  • Prevented multiple tagging-rules creation attempts when clicking the create button quickly.

  • Prevented multiple tag creation attempts when clicking the create button quickly.

  • Api breaking change: removed the /api/organizations/:organizationId/documents/search endpoint in favor of the existing /api/organizations/:organizationId/documents with an optional searchQuery query parameter. The new /api/organizations/:organizationId/documents endpoint now behave as the old /search endpoint, with all documents being returned when searchQuery is empty. Note that the response field totalCount of the old /search endpoint has been renamed to documentsCount in the new endpoint.

    Before:

    GET /api/organizations/:organizationId/documents/search?searchQuery=invoice&pageIndex=1&pageSize=20
    Response: {
      documents: Document[];
      totalCount: number;
    }
    
    GET /api/organizations/:organizationId/documents?pageIndex=1&pageSize=20
    Response: {
      documents: Document[];
      documentsCount: number;
    }
    

    After:

    GET /api/organizations/:organizationId/documents?searchQuery=invoice&pageIndex=1&pageSize=20
    Response: {
      documents: Document[];
      documentsCount: number;
    }
    
  • Security fix: prevented unauthorized listing to organization tags and webhooks. An authenticated user could list the tags and webhooks of an organization they are not a member of by sending requests to the corresponding endpoints by knowing the organization ID. Credit to Sergio Cabrera, security researcher, for responsibly disclosing this vulnerability.

v26.1.0

v26.0.0

  • API Breaking Change: Document search endpoint now returns complete documents along with total count matching the search query, and no longer nests results under searchResults.

    Before:

    // GET /api/organizations/:organizationId/documents/search?searchQuery=foobar
    {
      searchResults: {
        documents: [
          { id: 'doc_1', name: 'Document 1.pdf' },
          { id: 'doc_2', name: 'Document 2.pdf' },
        ],
      },
    }
    

    After:

    // GET /api/organizations/:organizationId/documents/search?searchQuery=foobar
    {
      documents: [
        { id: 'doc_1', name: 'Document 1.pdf', mimeType: 'application/pdf' /* ...otherProps */ },
        { id: 'doc_2', name: 'Document 2.pdf', mimeType: 'application/pdf' /* ...otherProps */ },
      ],
      totalCount: 42,
    }
    
  • Added a "Show more results" option in quick search when there is more document not displayed

  • Improved search speed by using document and organization ids in index The first restart after updating may take up to few minutes as the search index is rebuilt

  • The documents page can now be used with advanced search queries

  • Auto assign admin role to the first user registering

  • Added about page and modal with version informations

  • Added a dedicated increased timeout for the document upload route

  • Added a feedback message upon request timeout

  • Added support for two factor authentication

  • Organizations listing and details in the admin dashboard

  • Added advanced search syntax support

  • Properly cleanup orphan file when the same document exists in trash

  • Added query params sync for the search query in the documents search page for deep linking and browser state navigation

  • Removed the possibility to filter by tag in the /api/organizations/:organizationId/documents route, use the /api/organizations/:organizationId/documents/search route instead.

    # Before:
    GET /api/organizations/:organizationId/documents?tags=yourTagId
    
    # After:
    GET /api/organizations/:organizationId/documents/search?query=tag:yourTagNameOrId
    
  • Changed config key config.server.routeTimeoutMs to config.server.defaultRouteTimeoutMs (env variable remains the same)

  • Added api endpoint to check current API key (GET /api/api-keys/current)

v25.12.0

v25.11.0

v25.10.2

v25.10.1

v25.10.0

v0.9.6

v0.9.5

v0.9.4

v0.9.3

  • Added the possibility to define patterns for email intake username generation

  • Split the intake-email username generation from the email address creation, some changes regarding the configuration when using the random driver.

    # Old configuration
    INTAKE_EMAILS_DRIVER=random-username
    INTAKE_EMAILS_EMAIL_GENERATION_DOMAIN=mydomain.com
    
    # New configuration
    INTAKE_EMAILS_DRIVER=catch-all
    INTAKE_EMAILS_CATCH_ALL_DOMAIN=mydomain.com
    INTAKE_EMAILS_USERNAME_DRIVER=random
    
  • Added the possibility to configure OwlRelay domain

v0.9.2

v0.9.1

v0.9.0

v0.8.2

v0.8.1

v0.8.0

v0.7.0

v0.6.4

v0.6.3

v0.6.2

v0.6.1

v0.6.0

v0.5.1

v0.5.0

v0.4.0