Here is the combined list of vulnerabilities, formatted as markdown, with duplicate vulnerabilities removed and information merged where applicable:
-
Description:
- An attacker can exploit the lack of CSRF protection in the
follow_unfollow
view to perform unauthorized follow or unfollow actions on behalf of a logged-in user. - Step 1: Attacker crafts a malicious web page containing a form that automatically submits a POST request to the
/follow/
or/unfollow/
endpoint of the application. This form will target a specific content type and object ID to be followed or unfollowed. The form will not include a valid CSRF token. - Step 2: Attacker tricks a logged-in user into visiting this malicious web page (e.g., through phishing, social engineering, or embedding the form in a compromised website).
- Step 3: When the user visits the page, the malicious form automatically submits the POST request to the application in the user's session.
- Step 4: Due to the
@csrf_exempt
decorator on thefollow_unfollow
view, the application does not validate the CSRF token in the request. - Step 5: The application processes the request, leading to an unintended follow or unfollow action being performed by the logged-in user without their explicit consent or knowledge.
- An attacker can exploit the lack of CSRF protection in the
-
Impact:
- An attacker can arbitrarily manipulate a user's follow list.
- This can be exploited to:
- Force users to follow malicious actors, leading to spam or disinformation in their activity streams.
- Force users to unfollow legitimate actors, disrupting their intended activity stream and potentially causing them to miss important updates.
- Manipulation of a user’s activity stream or social graph may result—potentially exposing confidential relationships or simply degrading trust in the service.
-
Vulnerability Rank: High
-
Currently Implemented Mitigations:
- None. The
@csrf_exempt
decorator inactstream/views.py
explicitly disables CSRF protection for thefollow_unfollow
view. - The endpoint does enforce that the requester must be logged in (via the
@login_required
decorator).
- None. The
-
Missing Mitigations:
- CSRF protection should be enabled for the
follow_unfollow
view. - Remove the
@csrf_exempt
decorator from thefollow_unfollow
view inactstream/views.py
. - Ensure that the view correctly handles CSRF tokens, either by using Django's
csrf_protect
decorator or by ensuring that templates used for these actions include the{% csrf_token %}
tag in forms. - Alternatively, replace
@csrf_exempt
with an explicit, alternative secure token‐based protection.
- CSRF protection should be enabled for the
-
Preconditions:
- The attacker requires a logged-in user to visit a malicious webpage or trigger a malicious request.
- The attacker needs to know the
content_type_id
andobject_id
of the object to be followed or unfollowed. This information can often be easily obtained or guessed. - The victim must be an authenticated user in the web application.
-
Source code analysis:
- File:
/code/actstream/views.py
from django.views.decorators.csrf import csrf_exempt from django.contrib.auth.decorators import login_required @login_required @csrf_exempt # Vulnerability: CSRF protection is disabled def follow_unfollow(request, content_type_id, object_id, flag=None, do_follow=True, actor_only=True): """ Creates or deletes the follow relationship between ``request.user`` and the actor defined by ``content_type_id``, ``object_id``. """ # ... function logic ...
- The
@csrf_exempt
decorator, located directly above thefollow_unfollow
function definition, explicitly disables Django's built-in CSRF protection for this view. This means that requests to this view are not checked for a valid CSRF token, making it susceptible to CSRF attacks. - In
/code/actstream/views.py
, thefollow_unfollow
function is defined as shown above. Notice that while the view properly checks that the user is authenticated, the@csrf_exempt
decorator removes the Django CSRF safeguard.
- File:
-
Security test case:
- Step 1: Log in to the application as a test user.
- Step 2: Identify the
content_type_id
for 'User' and theobject_id
of another user (e.g., user with username 'Two'). You can findcontent_type_id
by inspecting the database tabledjango_content_type
or by accessing admin panel. Let's assumecontent_type_id
for 'User' is 'X' andobject_id
for 'Two' is 'Y'. - Step 3: Create an HTML file (e.g.,
csrf_test.html
) with the following content:
<html> <body> <form action="/follow/X/Y/" method="POST" id="csrf-test-form"> <input type="hidden" name="next" value="/"/> <input type="submit" value="Follow User Two" /> </form> <script> document.getElementById('csrf-test-form').submit(); </script> </body> </html>
- Step 4: Serve this HTML file via a simple HTTP server or upload it to a publicly accessible web hosting.
- Step 5: As the logged-in test user, access the URL of the
csrf_test.html
file in your browser. - Step 6: Observe the application's behavior. After accessing the page, navigate to your user profile or activity stream within the application and verify if you are now following user 'Two'.
- Expected result: You will be successfully following user 'Two' even though the form submission did not include a CSRF token. This confirms the CSRF vulnerability in the
follow_unfollow
view. - Alternatively:
- Log in as a valid user on the target application.
- From an external (malicious) webpage, automatically submit a POST request to a URL such as:
https://target.example.com/follow/5/23/?flag=malicious
- Verify in the application that the logged-in user’s “follow” relationship was modified even though the request did not originate from a trusted source.
- Document that the absence of CSRF token validation enabled this unauthorized state change.
-
Description:
- In the helper function
respond
(located in/code/actstream/views.py
), the code checks for a parameter namednext
(from either GET or POST) and, if present, immediately returns an HTTP redirect to that URL without any form of validation. An attacker can supply an arbitrary external URL into thenext
parameter. When a victim follows a link that uses this endpoint, they are unknowingly redirected to a potentially malicious site.
- In the helper function
-
Impact:
- Phishing attacks become possible by redirecting authenticated users to attacker‑controlled websites.
- The attacker may leverage the redirect to simulate legitimate behavior and harvest credentials or other sensitive data.
-
Vulnerability Rank: High
-
Currently Implemented Mitigations:
- None specific—the endpoint blindly uses the supplied
next
value.
- None specific—the endpoint blindly uses the supplied
-
Missing Mitigations:
- Validate that the value of the
next
parameter is a relative URL or belongs to an approved, trusted domain. - Alternatively, remove support for an externally provided
next
parameter on state‑changing endpoints.
- Validate that the value of the
-
Preconditions:
- The victim must be already authenticated.
- The attacker must provide a link with a crafted
next
parameter (e.g., through phishing email or advertisement).
-
Source code analysis:
- The
respond
function is defined as follows in/code/actstream/views.py
:
def respond(request, code): redirect = request.GET.get('next', request.POST.get('next')) if redirect: return HttpResponseRedirect(redirect) return type('Response%d' % code, (HttpResponse, ), {'status_code': code})()
- No checks or sanitization of the “next” parameter are performed; it is passed directly as the destination in the HTTP redirect.
- The
-
Security test case:
- Step 1: As an attacker, create a URL such as:
https://target.example.com/follow/5/23/?next=https://malicious.example.com
- Step 2: Send the link to a victim (e.g., via email or social media) who is likely to be logged in at the target site.
- Step 3: When the victim clicks the link, observe that after the follow/unfollow action the browser is redirected to
https://malicious.example.com
. - Step 4: Confirm the absence of any validation on the redirect destination and document the open redirect vulnerability.
- Step 1: As an attacker, create a URL such as:
-
Description:
- The settings file (located at
/code/runtests/settings.py
) contains the following lines:
DEBUG = True SECRET_KEY = 'secret-key'
- Running Django in DEBUG mode with a known, hard‑coded secret key is acceptable only in a secure development or testing environment. If these settings are mistakenly deployed in production, they expose the application to several attacks.
- The settings file (located at
-
Impact:
- Detailed error pages (including environment information, stack traces, and configuration details) are exposed to end‑users upon encountering any error.
- The static, well‑known secret key compromises the integrity of cryptographic operations such as session signing and CSRF token generation. An attacker may then forge session cookies or CSRF tokens, leading to session hijacking and further exploitation of the application.
-
Vulnerability Rank: Critical
-
Currently Implemented Mitigations:
- A comment in the file warns: "Always for debugging, dont use the runtests app in production!" However, this does not enforce the settings dynamically.
-
Missing Mitigations:
- Ensure that the production environment sets
DEBUG = False
and uses a cryptographically strong, secret secret key (typically sourced from environment variables or a secure secrets store). - Remove or isolate the testing configuration from production deployments.
- Ensure that the production environment sets
-
Preconditions:
- The application is deployed to a production or publicly accessible environment using the settings provided in
/code/runtests/settings.py
. - An attacker may trigger error pages or analyze session cookies without the benefit of unique secrets.
- The application is deployed to a production or publicly accessible environment using the settings provided in
-
Source code analysis:
- The settings file sets:
DEBUG = True SECRET_KEY = 'secret-key'
- This configuration is inherently insecure for production and exposes the system to multiple attack vectors if not overwritten by environment‑specific settings.
-
Security test case:
- Step 1: Deploy the application using the current settings without modifications in an environment that is accessible to users.
- Step 2: Deliberately trigger a server error (for example, by accessing a non‑existent URL).
- Step 3: Verify that Django’s detailed debug error page (including stack trace and configuration information) is displayed.
- Step 4: Inspect session cookies in the browser to confirm that they are signed using the known secret key.
- Step 5: Attempt to forge a session cookie using the known secret key to demonstrate that an active session can be impersonated.
- Step 6: Document that the use of
DEBUG = True
and a hard‑coded secret key exposes significant risk if left in production.
-
Description:
-
The
follow_unfollow
view inactstream/views.py
allows users to create or delete "follow" relationships between a user and an arbitrary object. This view usescontent_type_id
andobject_id
from the URL to identify the object to be followed/unfollowed. However, it lacks proper authorization checks to ensure that the user initiating the follow/unfollow action is authorized to interact with the target object in this manner. An attacker could potentially manipulate thecontent_type_id
andobject_id
parameters to follow or unfollow objects they should not have access to, leading to unauthorized access to activity streams related to those objects. -
Step-by-step trigger:
- An attacker identifies a valid
content_type_id
andobject_id
of an object they are not supposed to follow (e.g., a private user profile, a restricted group, etc.). Let's assume this object is of ContentType 'testapp.Player' with pk=10. - The attacker, logged in as a regular user, crafts a request to the
/follow/<content_type_id>/<object_id>/
endpoint, replacing<content_type_id>
with the ContentType ID of 'testapp.Player' and<object_id>
with '10'. For example, if ContentType ID for 'testapp.Player' is 'X', the attacker would access/follow/X/10/
. - The
follow_unfollow
view, without proper authorization checks, will create a "follow" relationship between the attacker's user and the 'testapp.Player' object with pk=10. - The attacker can now access activity streams related to the followed object, potentially gaining unauthorized insights into activities associated with that object.
- Similarly, an attacker could use the
/unfollow/<content_type_id>/<object_id>/
endpoint to unfollow objects, even if they were not initially authorized to establish the follow relationship, or if removing the follow relationship has unintended consequences.
- An attacker identifies a valid
-
-
Impact:
- Information Disclosure: An attacker can gain unauthorized access to activity streams of objects they are not intended to follow. This can reveal sensitive information about the followed objects, their activities, and interactions with other users or objects within the application.
- Data Manipulation (Indirect): While not direct data manipulation of the target object, the ability to follow/unfollow objects without authorization can disrupt the intended activity stream behavior for users and potentially lead to confusion or misrepresentation of user activity.
-
Vulnerability Rank: High
-
Currently Implemented Mitigations:
- Login Required Decorator: The
follow_unfollow
view is protected by the@login_required
decorator, ensuring that only authenticated users can access the functionality. However, this only verifies authentication, not authorization to follow/unfollow specific objects. - CSRF Protection: The
@csrf_exempt
decorator is used because the view is intended to be used with POST requests (though GET is also possible in the current code). CSRF protection is generally enabled by Django middleware. This protects against CSRF attacks but does not mitigate IDOR.
- Login Required Decorator: The
-
Missing Mitigations:
- Authorization Checks: The most critical missing mitigation is authorization checks within the
follow_unfollow
view. Before creating or deleting a follow relationship, the application should verify if the logged-in user has the necessary permissions to follow or unfollow the specified object. This check should be context-aware and depend on the application's specific access control requirements. For instance, it might involve checking object-level permissions or enforcing business logic rules related to following/unfollowing.
- Authorization Checks: The most critical missing mitigation is authorization checks within the
-
Preconditions:
- The application must have publicly accessible endpoints for following and unfollowing objects, which are configured by default in
actstream/urls.py
. - An attacker must be a registered and logged-in user of the application.
- The attacker needs to know or guess valid
content_type_id
andobject_id
values. ContentType IDs are usually sequential integers and can be easily discovered. Object IDs can also be discovered or brute-forced depending on the application.
- The application must have publicly accessible endpoints for following and unfollowing objects, which are configured by default in
-
Source code analysis:
- File:
/code/actstream/views.py
from django.shortcuts import get_object_or_404 from django.http import HttpResponseRedirect, HttpResponse from django.contrib.auth.decorators import login_required from django.contrib.contenttypes.models import ContentType from django.views.decorators.csrf import csrf_exempt from actstream import actions @login_required @csrf_exempt def follow_unfollow(request, content_type_id, object_id, flag=None, do_follow=True, actor_only=True): ctype = get_object_or_404(ContentType, pk=content_type_id) instance = get_object_or_404(ctype.model_class(), pk=object_id) flag = flag or '' if do_follow: actions.follow(request.user, instance, actor_only=actor_only, flag=flag) return respond(request, 201) actions.unfollow(request.user, instance, flag=flag) return respond(request, 204)
- Code Walkthrough:
- The
follow_unfollow
view is decorated with@login_required
, which ensures that only authenticated users can access this view. - It retrieves
content_type_id
andobject_id
from the URL parameters. get_object_or_404(ContentType, pk=content_type_id)
fetches the ContentType based on the provided ID.get_object_or_404(ctype.model_class(), pk=object_id)
fetches the actual object instance using the retrieved ContentType and the providedobject_id
.- If
do_follow
is True (default for/follow/
URLs), it callsactions.follow(request.user, instance, ...)
to create a follow relationship. - If
do_follow
is False (for/unfollow/
URLs), it callsactions.unfollow(request.user, instance, ...)
to delete a follow relationship. - Crucially, there are no authorization checks before calling
actions.follow
oractions.unfollow
.
- The
- File:
-
Security test case:
-
Pre-requisites:
- Ensure the test application includes the 'actstream' app and has the
actstream.urls
included in its URL configuration. - Create a model in the test application, e.g., 'testapp.Player', and register it with actstream.
- Create a few instances of 'testapp.Player' objects in the database.
- Create two test users: 'attacker' and 'victim'.
- Ensure the test application includes the 'actstream' app and has the
-
Steps:
- Log in to the test application as the 'attacker' user.
- Identify the ContentType ID for 'testapp.Player'. Let's assume it is 'X'.
- Identify the object ID of a 'testapp.Player' instance that the 'attacker' user should not be able to follow directly. Let's assume there is a 'testapp.Player' object with pk=1, representing a "private" player profile.
- Craft a GET request to the follow URL using the identified ContentType ID and object ID:
/follow/X/1/
. - Send the request to the application.
- Verify the HTTP response status code is 201 (Created).
- Log in to the Django admin panel as a superuser.
- Navigate to the Actstream Follows section in the admin panel (
/admin/actstream/follow/
). - Search for a Follow object where:
- User is 'attacker'
- Content Type is 'testapp | player'
- Object ID is '1'
- Verify that such a Follow object exists. This confirms that the 'attacker' user has successfully followed the 'testapp.Player' object with pk=1, even without explicit authorization to do so.
- (Optional) Access the activity stream of the 'attacker' user and confirm that actions related to the followed 'testapp.Player' object might now be visible.
- Repeat steps with
/unfollow/X/1/
and verify response code 204 and absence of the Follow object in the admin panel to test unauthorized unfollowing.
-
This combined list contains all unique vulnerabilities from the provided lists, formatted as requested with descriptions, impacts, ranks, mitigations, preconditions, source code analysis, and security test cases for each.