Skip to content

[Feature] Allowlist for Scheduled Tasks #911

Description

@chrismaddalena

Feature Description

Modify Ghostwriter’s Django-Q scheduled task administration flow to support an allowlist of approved scheduled task callables.

Django-Q scheduled tasks currently allow an administrator to specify a dotted Python function path, arguments, and an optional hook. Django-Q then imports and executes that callable through the worker process.

This behavior is part of Django-Q’s intended design and is useful for Ghostwriter because it allows trusted administrators to schedule documented Ghostwriter background tasks and deployment-specific maintenance tasks. However, because the callable path is administrator-controlled, the feature can also be misused if a Django superuser account is compromised or if a malicious insider has superuser access.

This issue proposes adding a defense-in-depth control that limits scheduled task execution to known-good callables.

Are you intending to implement this feature?

Open for discussion.

Current Behavior

Ghostwriter exposes Django-Q scheduled tasks through the Django admin interface.

A Django superuser can create or modify a scheduled task by specifying:

  • A function path
  • Arguments
  • Keyword arguments
  • An optional hook
  • Schedule timing and repeat behavior

Django-Q accepts the configured function path and executes it on schedule using the Django-Q worker.

This gives Django superusers a powerful administrative capability. In Ghostwriter’s current trust model, Django superusers are treated as fully trusted application administrators with complete access to Ghostwriter.

Desired Behavior

Ghostwriter should optionally restrict Django-Q scheduled tasks to an allowlist of approved callable paths.

For example, Ghostwriter could allow documented background task functions while rejecting arbitrary importable Python callables that are not intended to be used as scheduled tasks.

A rejected task should fail validation before it is saved or executed.

Example desired behavior:

  • Allowed: documented Ghostwriter background task functions
  • Allowed: explicitly configured deployment-specific maintenance functions
  • Rejected: arbitrary Python callables outside the allowlist

This would not remove the need to trust Django superusers, but it would add a guardrail against accidental misuse, compromised administrator sessions, and malicious administrators who do not also control the deployment environment.

Use Case

A community member raised a concern that the existing Django-Q scheduled task feature could be misused by a compromised Django superuser account or a malicious insider.

An allowlist would reduce that risk by ensuring that only known-good scheduled task functions can be launched through the Django admin interface.

For example, if the allowlist only contained Ghostwriter’s documented scheduled task functions, an administrator attempting to configure an unrelated Python callable would receive a validation error and the task would not be saved or executed.

This would be especially useful in deployments where:

  • Django superusers manage Ghostwriter application data but do not have host-level access
  • Organizations want stronger separation between application administration and runtime code execution
  • Operators want to reduce the blast radius of a compromised Django superuser account
  • Teams want scheduled tasks to be limited to documented and reviewed maintenance actions

Implementation Suggestions

Django-Q does not appear to provide a built-in allowlist mechanism for scheduled task callables, so Ghostwriter would likely need to implement this as an application-level control.

Potential approaches:

Settings-based allowlist

Add a Ghostwriter setting for allowed scheduled task callables.

Example:

GHOSTWRITER_DJANGO_Q_ALLOWED_SCHEDULE_FUNCS = [
    "ghostwriter.reporting.tasks.example_task",
    "ghostwriter.shepherd.tasks.example_task",
]

Additional Information

Part of this issue is placing the trust boundary. In Ghostwriter, we treat the administrator (a Django user with the superuser tag) as the most trusted and privileged entity in the application. Placing guardrails isn't a bad idea, but the guradrails will likely be within the admin's influence. We'd have to take more drastic action to eliminate this capability.

For example, with the allowlist concept, an admin with access to the host server could add unwanted commands to this allowlist. Admins without access to the host server would be bound to the allowlist.

Metadata

Metadata

Labels

enhancementNew feature or request

Fields

No fields configured for Feature.

Projects

Status
No status

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions