Skip to content

Conversation

@ibi420
Copy link

@ibi420 ibi420 commented May 7, 2025

This pull request addresses the issue of malicious code execution in PDF files.

No new dependencies have been introduced, and this change is non-breaking. It is compatible with version 9.x.

Type of Change

  • 🐞 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 💥 Breaking change (fix or feature that may break existing functionality)
  • 📚 Documentation update

How Has This Been Tested?

This fix was tested by creating a poisoned PDF and uploading it to Ontrack.

For a demo, see the video run-through:
Video demo

Developer Checklist

  • Code adheres to project style guidelines
  • Performed self-review and cleaned up the code
  • Added comments in complex sections of the code
  • Updated relevant documentation, if applicable
  • No new warnings introduced
  • Added tests to validate that the fix is effective or the feature works
  • Created or extended unit tests to cover new additions
  • Ensured that new and existing unit tests pass locally
  • Merged and published any dependent changes in downstream modules
  • I have requested a review from @returnMarcco and @theiris6

@ibi420 ibi420 marked this pull request as draft May 12, 2025 12:49
@ibi420 ibi420 marked this pull request as ready for review May 12, 2025 12:50
@returnMarcco
Copy link

Hi Ibi,

When attempting to test these changes, I have been unsuccessful in being to upload any file, including PDF file types. I tested on the 9.x branch and was able to upload files successfully, but I wasn't able to on your feature branch. Please see the below screenshot:

Screenshot 2025-05-13 004728

Can you please test whether you are able to upload files on the fix/malicious-code-execution branch and let me know how you progress, then I can continue with this review.

Cheers

@ibi420
Copy link
Author

ibi420 commented May 13, 2025

@returnMarcco I have gone through it and reset my dev environment, but everything is working as expected. In order for me to help you discover the root cause of this issue, I would suggest that you look through the development logs of the back end as you start to upload a PDF. I have added loggers to the script to track each step of the sanitisation process. You should have something like this. image
Please share the information on the logs; this will enable me to discover if it is due to my code or something else. There is also a chance the function rejects your PDF because it cannot verify it. Before sanitisation starts, the PDF is validated. All in all, please clear your dev logs and retry to upload the PDF or make a different PDF and retry to upload it (ensure you clear the logs right before you upload it to make it easier to find the relevant logs). The logs will give more clarification on what is wrong. I'm not sure this will make a difference, but I swap branches using the GitHub Desktop application, and I have to manually restart the terminals for any changes to take effect. Is it possible this is what is preventing you from testing?

@returnMarcco
Copy link

Hey @ibi420,

Thanks for the response. As mentioned in our private discussion, I will attempt to test your changes again as soon as possible and keep you updated here.

Cheers

@returnMarcco
Copy link

returnMarcco commented May 13, 2025

Hi ibi,

To try rectify the issue, I've completed the following with no success:

  • I've deleted the local branches containing your changes and refetched them
  • I've ensured doubtfire-web and doubtfire-deploy are on the fix/malicious-code-execution branch
  • I've ensured doubtfire-deploy is on the 9.x branch
  • I've restarted my docker container (especially when switching branches)
  • I've rebuilt the app
  • I've used multiple, known working PDF files, including that which the author has provided

I'll provide a snippet of the logs that are generated when attempting to upload a PDF file via the comments section of the unit you stipulated in your walkthrough video (Object Oriented Programming - Assignment 4):

  • Judging by the logs below, the PDF is failing sanitization. An exception is also thrown in the task::add_comment_with_attachment method.

  • Its important to note that switching to the base 9.x branch allows me to upload files without an issue.

  • I can upload other file types (non-PDF) without logging any errors.

I'm going to let Nebula know that for now, I'm not able to progress on this review for now. I'm interested to see if the other reviewer for this PR finds success. Please keep me updated with any findings, and I'm always ready to get back to this review.

Cheers

2025-05-13 21:41:26 +1000,127.0.0.1,DEBUG:   �[1m�[35mSQL (0.3ms)�[0m  �[1m�[34mSELECT DISTINCT `users`.`id` FROM `users` LEFT OUTER JOIN `roles` ON `roles`.`id` = `users`.`role_id` LEFT OUTER JOIN `auth_tokens` ON `auth_tokens`.`user_id` = `users`.`id` WHERE `users`.`username` = 'student_1' LIMIT 1�[0m
2025-05-13 21:41:26 +1000,127.0.0.1,DEBUG:   ↳ app/helpers/authentication_helpers.rb:56:in `current_user'
2025-05-13 21:41:26 +1000,127.0.0.1,DEBUG:   �[1m�[35mSQL (0.3ms)�[0m  �[1m�[34mSELECT `users`.`id` AS t0_r0, `users`.`email` AS t0_r1, `users`.`encrypted_password` AS t0_r2, `users`.`reset_password_token` AS t0_r3, `users`.`reset_password_sent_at` AS t0_r4, `users`.`remember_created_at` AS t0_r5, `users`.`sign_in_count` AS t0_r6, `users`.`current_sign_in_at` AS t0_r7, `users`.`last_sign_in_at` AS t0_r8, `users`.`current_sign_in_ip` AS t0_r9, `users`.`last_sign_in_ip` AS t0_r10, `users`.`created_at` AS t0_r11, `users`.`updated_at` AS t0_r12, `users`.`first_name` AS t0_r13, `users`.`last_name` AS t0_r14, `users`.`username` AS t0_r15, `users`.`nickname` AS t0_r16, `users`.`unlock_token` AS t0_r17, `users`.`role_id` AS t0_r18, `users`.`receive_task_notifications` AS t0_r19, `users`.`receive_feedback_notifications` AS t0_r20, `users`.`receive_portfolio_notifications` AS t0_r21, `users`.`opt_in_to_research` AS t0_r22, `users`.`has_run_first_time_setup` AS t0_r23, `users`.`login_id` AS t0_r24, `users`.`student_id` AS t0_r25, `users`.`tii_eula_version` AS t0_r26, `users`.`tii_eula_date` AS t0_r27, `users`.`tii_eula_version_confirmed` AS t0_r28, `roles`.`id` AS t1_r0, `roles`.`name` AS t1_r1, `roles`.`description` AS t1_r2, `roles`.`created_at` AS t1_r3, `roles`.`updated_at` AS t1_r4, `auth_tokens`.`id` AS t2_r0, `auth_tokens`.`auth_token_expiry` AS t2_r1, `auth_tokens`.`user_id` AS t2_r2, `auth_tokens`.`authentication_token` AS t2_r3 FROM `users` LEFT OUTER JOIN `roles` ON `roles`.`id` = `users`.`role_id` LEFT OUTER JOIN `auth_tokens` ON `auth_tokens`.`user_id` = `users`.`id` WHERE `users`.`username` = 'student_1' AND `users`.`id` = 25�[0m
2025-05-13 21:41:26 +1000,127.0.0.1,DEBUG:   ↳ app/helpers/authentication_helpers.rb:56:in `current_user'
2025-05-13 21:41:26 +1000,127.0.0.1,INFO: Authenticated student_1 from 127.0.0.1
2025-05-13 21:41:26 +1000,127.0.0.1,DEBUG:   �[1m�[36mProject Load (0.2ms)�[0m  �[1m�[34mSELECT `projects`.* FROM `projects` WHERE `projects`.`id` = 18 LIMIT 1�[0m
2025-05-13 21:41:26 +1000,127.0.0.1,DEBUG:   ↳ app/api/task_comments_api.rb:18:in `block in <class:TaskCommentsApi>'
2025-05-13 21:41:26 +1000,127.0.0.1,DEBUG:   �[1m�[36mUnit Load (0.2ms)�[0m  �[1m�[34mSELECT `units`.* FROM `units` WHERE `units`.`id` = 2 LIMIT 1�[0m
2025-05-13 21:41:26 +1000,127.0.0.1,DEBUG:   ↳ app/api/task_comments_api.rb:19:in `block in <class:TaskCommentsApi>'
2025-05-13 21:41:26 +1000,127.0.0.1,DEBUG:   �[1m�[36mTaskDefinition Load (0.2ms)�[0m  �[1m�[34mSELECT `task_definitions`.* FROM `task_definitions` WHERE `task_definitions`.`unit_id` = 2 AND `task_definitions`.`id` = 41 ORDER BY start_date ASC, abbreviation ASC LIMIT 1�[0m
2025-05-13 21:41:26 +1000,127.0.0.1,DEBUG:   ↳ app/api/task_comments_api.rb:19:in `block in <class:TaskCommentsApi>'
2025-05-13 21:41:26 +1000,127.0.0.1,DEBUG:   �[1m�[35mCACHE SQL (0.0ms)�[0m  �[1m�[34mSELECT DISTINCT `users`.`id` FROM `users` LEFT OUTER JOIN `roles` ON `roles`.`id` = `users`.`role_id` LEFT OUTER JOIN `auth_tokens` ON `auth_tokens`.`user_id` = `users`.`id` WHERE `users`.`username` = 'student_1' LIMIT 1�[0m
2025-05-13 21:41:26 +1000,127.0.0.1,DEBUG:   ↳ app/helpers/authentication_helpers.rb:56:in `current_user'
2025-05-13 21:41:26 +1000,127.0.0.1,DEBUG:   �[1m�[35mCACHE SQL (0.0ms)�[0m  �[1m�[34mSELECT `users`.`id` AS t0_r0, `users`.`email` AS t0_r1, `users`.`encrypted_password` AS t0_r2, `users`.`reset_password_token` AS t0_r3, `users`.`reset_password_sent_at` AS t0_r4, `users`.`remember_created_at` AS t0_r5, `users`.`sign_in_count` AS t0_r6, `users`.`current_sign_in_at` AS t0_r7, `users`.`last_sign_in_at` AS t0_r8, `users`.`current_sign_in_ip` AS t0_r9, `users`.`last_sign_in_ip` AS t0_r10, `users`.`created_at` AS t0_r11, `users`.`updated_at` AS t0_r12, `users`.`first_name` AS t0_r13, `users`.`last_name` AS t0_r14, `users`.`username` AS t0_r15, `users`.`nickname` AS t0_r16, `users`.`unlock_token` AS t0_r17, `users`.`role_id` AS t0_r18, `users`.`receive_task_notifications` AS t0_r19, `users`.`receive_feedback_notifications` AS t0_r20, `users`.`receive_portfolio_notifications` AS t0_r21, `users`.`opt_in_to_research` AS t0_r22, `users`.`has_run_first_time_setup` AS t0_r23, `users`.`login_id` AS t0_r24, `users`.`student_id` AS t0_r25, `users`.`tii_eula_version` AS t0_r26, `users`.`tii_eula_date` AS t0_r27, `users`.`tii_eula_version_confirmed` AS t0_r28, `roles`.`id` AS t1_r0, `roles`.`name` AS t1_r1, `roles`.`description` AS t1_r2, `roles`.`created_at` AS t1_r3, `roles`.`updated_at` AS t1_r4, `auth_tokens`.`id` AS t2_r0, `auth_tokens`.`auth_token_expiry` AS t2_r1, `auth_tokens`.`user_id` AS t2_r2, `auth_tokens`.`authentication_token` AS t2_r3 FROM `users` LEFT OUTER JOIN `roles` ON `roles`.`id` = `users`.`role_id` LEFT OUTER JOIN `auth_tokens` ON `auth_tokens`.`user_id` = `users`.`id` WHERE `users`.`username` = 'student_1' AND `users`.`id` = 25�[0m
2025-05-13 21:41:26 +1000,127.0.0.1,DEBUG:   ↳ app/helpers/authentication_helpers.rb:56:in `current_user'
2025-05-13 21:41:26 +1000,127.0.0.1,DEBUG:   �[1m�[36mUser Load (0.3ms)�[0m  �[1m�[34mSELECT `users`.* FROM `users` WHERE `users`.`id` = 25 LIMIT 1�[0m
2025-05-13 21:41:26 +1000,127.0.0.1,DEBUG:   ↳ app/models/project.rb:188:in `student'
2025-05-13 21:41:26 +1000,127.0.0.1,DEBUG: Finding task A4 for project 18 - Ethelyn Lindgren (student_1) COS20007
2025-05-13 21:41:26 +1000,127.0.0.1,DEBUG:   �[1m�[36mTask Load (0.3ms)�[0m  �[1m�[34mSELECT `tasks`.* FROM `tasks` WHERE `tasks`.`project_id` = 18 AND `tasks`.`task_definition_id` = 41 ORDER BY `tasks`.`id` ASC LIMIT 1�[0m
2025-05-13 21:41:26 +1000,127.0.0.1,DEBUG:   ↳ app/models/project.rb:618:in `task_for_task_definition'
2025-05-13 21:41:26 +1000,127.0.0.1,DEBUG:   �[1m�[35mCACHE SQL (0.0ms)�[0m  �[1m�[34mSELECT DISTINCT `users`.`id` FROM `users` LEFT OUTER JOIN `roles` ON `roles`.`id` = `users`.`role_id` LEFT OUTER JOIN `auth_tokens` ON `auth_tokens`.`user_id` = `users`.`id` WHERE `users`.`username` = 'student_1' LIMIT 1�[0m
2025-05-13 21:41:26 +1000,127.0.0.1,DEBUG:   ↳ app/helpers/authentication_helpers.rb:56:in `current_user'
2025-05-13 21:41:26 +1000,127.0.0.1,DEBUG:   �[1m�[35mCACHE SQL (0.0ms)�[0m  �[1m�[34mSELECT `users`.`id` AS t0_r0, `users`.`email` AS t0_r1, `users`.`encrypted_password` AS t0_r2, `users`.`reset_password_token` AS t0_r3, `users`.`reset_password_sent_at` AS t0_r4, `users`.`remember_created_at` AS t0_r5, `users`.`sign_in_count` AS t0_r6, `users`.`current_sign_in_at` AS t0_r7, `users`.`last_sign_in_at` AS t0_r8, `users`.`current_sign_in_ip` AS t0_r9, `users`.`last_sign_in_ip` AS t0_r10, `users`.`created_at` AS t0_r11, `users`.`updated_at` AS t0_r12, `users`.`first_name` AS t0_r13, `users`.`last_name` AS t0_r14, `users`.`username` AS t0_r15, `users`.`nickname` AS t0_r16, `users`.`unlock_token` AS t0_r17, `users`.`role_id` AS t0_r18, `users`.`receive_task_notifications` AS t0_r19, `users`.`receive_feedback_notifications` AS t0_r20, `users`.`receive_portfolio_notifications` AS t0_r21, `users`.`opt_in_to_research` AS t0_r22, `users`.`has_run_first_time_setup` AS t0_r23, `users`.`login_id` AS t0_r24, `users`.`student_id` AS t0_r25, `users`.`tii_eula_version` AS t0_r26, `users`.`tii_eula_date` AS t0_r27, `users`.`tii_eula_version_confirmed` AS t0_r28, `roles`.`id` AS t1_r0, `roles`.`name` AS t1_r1, `roles`.`description` AS t1_r2, `roles`.`created_at` AS t1_r3, `roles`.`updated_at` AS t1_r4, `auth_tokens`.`id` AS t2_r0, `auth_tokens`.`auth_token_expiry` AS t2_r1, `auth_tokens`.`user_id` AS t2_r2, `auth_tokens`.`authentication_token` AS t2_r3 FROM `users` LEFT OUTER JOIN `roles` ON `roles`.`id` = `users`.`role_id` LEFT OUTER JOIN `auth_tokens` ON `auth_tokens`.`user_id` = `users`.`id` WHERE `users`.`username` = 'student_1' AND `users`.`id` = 25�[0m
2025-05-13 21:41:26 +1000,127.0.0.1,DEBUG:   ↳ app/helpers/authentication_helpers.rb:56:in `current_user'
2025-05-13 21:41:26 +1000,127.0.0.1,INFO: student_1 - added comment for task 221 (A4)
2025-05-13 21:41:26 +1000,127.0.0.1,DEBUG: Uploaded file is accepted
2025-05-13 21:41:26 +1000,127.0.0.1,DEBUG:   �[1m�[35mCACHE SQL (0.0ms)�[0m  �[1m�[34mSELECT DISTINCT `users`.`id` FROM `users` LEFT OUTER JOIN `roles` ON `roles`.`id` = `users`.`role_id` LEFT OUTER JOIN `auth_tokens` ON `auth_tokens`.`user_id` = `users`.`id` WHERE `users`.`username` = 'student_1' LIMIT 1�[0m
2025-05-13 21:41:26 +1000,127.0.0.1,DEBUG:   ↳ app/helpers/authentication_helpers.rb:56:in `current_user'
2025-05-13 21:41:26 +1000,127.0.0.1,DEBUG:   �[1m�[35mCACHE SQL (0.0ms)�[0m  �[1m�[34mSELECT `users`.`id` AS t0_r0, `users`.`email` AS t0_r1, `users`.`encrypted_password` AS t0_r2, `users`.`reset_password_token` AS t0_r3, `users`.`reset_password_sent_at` AS t0_r4, `users`.`remember_created_at` AS t0_r5, `users`.`sign_in_count` AS t0_r6, `users`.`current_sign_in_at` AS t0_r7, `users`.`last_sign_in_at` AS t0_r8, `users`.`current_sign_in_ip` AS t0_r9, `users`.`last_sign_in_ip` AS t0_r10, `users`.`created_at` AS t0_r11, `users`.`updated_at` AS t0_r12, `users`.`first_name` AS t0_r13, `users`.`last_name` AS t0_r14, `users`.`username` AS t0_r15, `users`.`nickname` AS t0_r16, `users`.`unlock_token` AS t0_r17, `users`.`role_id` AS t0_r18, `users`.`receive_task_notifications` AS t0_r19, `users`.`receive_feedback_notifications` AS t0_r20, `users`.`receive_portfolio_notifications` AS t0_r21, `users`.`opt_in_to_research` AS t0_r22, `users`.`has_run_first_time_setup` AS t0_r23, `users`.`login_id` AS t0_r24, `users`.`student_id` AS t0_r25, `users`.`tii_eula_version` AS t0_r26, `users`.`tii_eula_date` AS t0_r27, `users`.`tii_eula_version_confirmed` AS t0_r28, `roles`.`id` AS t1_r0, `roles`.`name` AS t1_r1, `roles`.`description` AS t1_r2, `roles`.`created_at` AS t1_r3, `roles`.`updated_at` AS t1_r4, `auth_tokens`.`id` AS t2_r0, `auth_tokens`.`auth_token_expiry` AS t2_r1, `auth_tokens`.`user_id` AS t2_r2, `auth_tokens`.`authentication_token` AS t2_r3 FROM `users` LEFT OUTER JOIN `roles` ON `roles`.`id` = `users`.`role_id` LEFT OUTER JOIN `auth_tokens` ON `auth_tokens`.`user_id` = `users`.`id` WHERE `users`.`username` = 'student_1' AND `users`.`id` = 25�[0m
2025-05-13 21:41:26 +1000,127.0.0.1,DEBUG:   ↳ app/helpers/authentication_helpers.rb:56:in `current_user'
2025-05-13 21:41:26 +1000,127.0.0.1,DEBUG:   �[1m�[36mTaskDefinition Load (0.3ms)�[0m  �[1m�[34mSELECT `task_definitions`.* FROM `task_definitions` WHERE `task_definitions`.`id` = 41 LIMIT 1�[0m
2025-05-13 21:41:26 +1000,127.0.0.1,DEBUG:   ↳ app/models/task.rb:393:in `group_task?'
2025-05-13 21:41:26 +1000,127.0.0.1,DEBUG: File MIME check failed
2025-05-13 21:41:26 +1000,127.0.0.1,DEBUG: File MIME check failed
2025-05-13 21:41:26 +1000,127.0.0.1,DEBUG: Starting PDF sanitization for /tmp/RackMultipart20250513-766-9lt8u4.pdf
2025-05-13 21:41:26 +1000,127.0.0.1,DEBUG: Validating PDF: /tmp/RackMultipart20250513-766-9lt8u4.pdf
2025-05-13 21:41:26 +1000,127.0.0.1,DEBUG: Running qpdf on: /tmp/RackMultipart20250513-766-9lt8u4.pdf
2025-05-13 21:41:26 +1000,127.0.0.1,DEBUG: Running QPDF on: /tmp/RackMultipart20250513-766-9lt8u4.pdf
2025-05-13 21:41:26 +1000,127.0.0.1,DEBUG: Running ghostscript on: /tmp/RackMultipart20250513-766-9lt8u4.pdf
2025-05-13 21:41:26 +1000,127.0.0.1,DEBUG: PDF sanitization failed: Failed to sanitize PDF
2025-05-13 21:41:26 +1000,127.0.0.1,ERROR: Unhandled exception: RuntimeError
2025-05-13 21:41:26 +1000,127.0.0.1,ERROR: #<RuntimeError: Unknown comment attachment type>
2025-05-13 21:41:26 +1000,127.0.0.1,ERROR: /workspace/doubtfire-api/app/models/task.rb:729:in `add_comment_with_attachment'\n/workspace/doubtfire-api/app/api/task_comments_api.rb:54:in `block in <class:TaskCommentsApi>'\n/home/vscode/.gems/ruby/3.3.0/gems/grape-2.0.0/lib/grape/endpoint.rb:58:in `call'\n/home/vscode/.gems/ruby/3.3.0/gems/grape-2.0.0/lib/grape/endpoint.rb:58:in `block (2 levels) in generate_api_method'\n/home/vscode/.gems/ruby/3.3.0/gems/activesupport-7.1.3.4/lib/active_support/notifications.rb:208:in `instrument'\n/home/vscode/.gems/ruby/3.3.0/gems/grape-2.0.0/lib/grape/endpoint.rb:57:in `block in generate_api_method'\n/home/vscode/.gems/ruby/3.3.0/gems/grape-2.0.0/lib/grape/endpoint.rb:328:in `execute'\n/home/vscode/.gems/ruby/3.3.0/gems/grape-2.0.0/lib/grape/endpoint.rb:260:in `block in run'\n/home/vscode/.gems/ruby/3.3.0/gems/activesupport-7.1.3.4/lib/active_support/notifications.rb:208:in `instrument'\n/home/vscode/.gems/ruby/3.3.0/gems/grape-2.0.0/lib/grape/endpoint.rb:240:in `run'\n/home/vscode/.gems/ruby/3.3.0/gems/grape-2.0.0/lib/grape/endpoint.rb:316:in `block in build_stack'\n/home/vscode/.gems/ruby/3.3.0/gems/grape-2.0.0/lib/grape/middleware/base.rb:36:in `call!'\n/home/vscode/.gems/ruby/3.3.0/gems/grape-2.0.0/lib/grape/middleware/base.rb:29:in `call'\n/home/vscode/.gems/ruby/3.3.0/gems/grape-2.0.0/lib/grape/middleware/error.rb:39:in `block in call!'\n/home/vscode/.gems/ruby/3.3.0/gems/grape-2.0.0/lib/grape/middleware/error.rb:38:in `catch'\n/home/vscode/.gems/ruby/3.3.0/gems/grape-2.0.0/lib/grape/middleware/error.rb:38:in `call!'\n/home/vscode/.gems/ruby/3.3.0/gems/grape-2.0.0/lib/grape/middleware/base.rb:29:in `call'\n/home/vscode/.gems/ruby/3.3.0/gems/rack-3.0.11/lib/rack/head.rb:15:in `call'\n/home/vscode/.gems/ruby/3.3.0/gems/grape-2.0.0/lib/grape/endpoint.rb:224:in `call!'\n/home/vscode/.gems/ruby/3.3.0/gems/grape-2.0.0/lib/grape/endpoint.rb:218:in `call'\n/home/vscode/.gems/ruby/3.3.0/gems/grape-2.0.0/lib/grape/router/route.rb:58:in `exec'\n/home/vscode/.gems/ruby/3.3.0/gems/grape-2.0.0/lib/grape/router.rb:120:in `process_route'\n/home/vscode/.gems/ruby/3.3.0/gems/grape-2.0.0/lib/grape/router.rb:74:in `block in identity'\n/home/vscode/.gems/ruby/3.3.0/gems/grape-2.0.0/lib/grape/router.rb:94:in `transaction'\n/home/vscode/.gems/ruby/3.3.0/gems/grape-2.0.0/lib/grape/router.rb:72:in `identity'\n/home/vscode/.gems/ruby/3.3.0/gems/grape-2.0.0/lib/grape/router.rb:56:in `block in call'\n/home/vscode/.gems/ruby/3.3.0/gems/grape-2.0.0/lib/grape/router.rb:136:in `with_optimization'\n/home/vscode/.gems/ruby/3.3.0/gems/grape-2.0.0/lib/grape/router.rb:55:in `call'\n/home/vscode/.gems/ruby/3.3.0/gems/grape-2.0.0/lib/grape/api/instance.rb:165:in `call'\n/home/vscode/.gems/ruby/3.3.0/gems/grape-2.0.0/lib/grape/api/instance.rb:70:in `call!'\n/home/vscode/.gems/ruby/3.3.0/gems/grape-2.0.0/lib/grape/api/instance.rb:65:in `call'\n/home/vscode/.gems/ruby/3.3.0/gems/grape-2.0.0/lib/grape/api.rb:81:in `call'\n/home/vscode/.gems/ruby/3.3.0/gems/actionpack-7.1.3.4/lib/action_dispatch/routing/mapper.rb:22:in `block in <class:Constraints>'\n/home/vscode/.gems/ruby/3.3.0/gems/actionpack-7.1.3.4/lib/action_dispatch/routing/mapper.rb:51:in `serve'\n/home/vscode/.gems/ruby/3.3.0/gems/actionpack-7.1.3.4/lib/action_dispatch/journey/router.rb:51:in `block in serve'\n/home/vscode/.gems/ruby/3.3.0/gems/actionpack-7.1.3.4/lib/action_dispatch/journey/router.rb:131:in `block in find_routes'\n/home/vscode/.gems/ruby/3.3.0/gems/actionpack-7.1.3.4/lib/action_dispatch/journey/router.rb:124:in `each'\n/home/vscode/.gems/ruby/3.3.0/gems/actionpack-7.1.3.4/lib/action_dispatch/journey/router.rb:124:in `find_routes'\n/home/vscode/.gems/ruby/3.3.0/gems/actionpack-7.1.3.4/lib/action_dispatch/journey/router.rb:32:in `serve'\n/home/vscode/.gems/ruby/3.3.0/gems/actionpack-7.1.3.4/lib/action_dispatch/routing/route_set.rb:882:in `call'\n/home/vscode/.gems/ruby/3.3.0/gems/warden-1.2.9/lib/warden/manager.rb:36:in `block in call'\n/home/vscode/.gems/ruby/3.3.0/gems/warden-1.2.9/lib/warden/manager.rb:34:in `catch'\n/home/vscode/.gems/ruby/3.3.0/gems/warden-1.2.9/lib/warden/manager.rb:34:in `call'\n/home/vscode/.gems/ruby/3.3.0/gems/rack-cors-2.0.2/lib/rack/cors.rb:102:in `call'\n/home/vscode/.gems/ruby/3.3.0/gems/rack-3.0.11/lib/rack/tempfile_reaper.rb:20:in `call'\n/home/vscode/.gems/ruby/3.3.0/gems/rack-3.0.11/lib/rack/etag.rb:29:in `call'\n/home/vscode/.gems/ruby/3.3.0/gems/rack-3.0.11/lib/rack/conditional_get.rb:43:in `call'\n/home/vscode/.gems/ruby/3.3.0/gems/rack-3.0.11/lib/rack/head.rb:15:in `call'\n/home/vscode/.gems/ruby/3.3.0/gems/actionpack-7.1.3.4/lib/action_dispatch/http/permissions_policy.rb:36:in `call'\n/home/vscode/.gems/ruby/3.3.0/gems/actionpack-7.1.3.4/lib/action_dispatch/http/content_security_policy.rb:33:in `call'\n/home/vscode/.gems/ruby/3.3.0/gems/rack-session-2.0.0/lib/rack/session/abstract/id.rb:272:in `context'\n/home/vscode/.gems/ruby/3.3.0/gems/rack-session-2.0.0/lib/rack/session/abstract/id.rb:266:in `call'\n/home/vscode/.gems/ruby/3.3.0/gems/actionpack-7.1.3.4/lib/action_dispatch/middleware/cookies.rb:689:in `call'\n/home/vscode/.gems/ruby/3.3.0/gems/activerecord-7.1.3.4/lib/active_record/migration.rb:655:in `call'\n/home/vscode/.gems/ruby/3.3.0/gems/actionpack-7.1.3.4/lib/action_dispatch/middleware/callbacks.rb:29:in `block in call'\n/home/vscode/.gems/ruby/3.3.0/gems/activesupport-7.1.3.4/lib/active_support/callbacks.rb:101:in `run_callbacks'\n/home/vscode/.gems/ruby/3.3.0/gems/actionpack-7.1.3.4/lib/action_dispatch/middleware/callbacks.rb:28:in `call'\n/home/vscode/.gems/ruby/3.3.0/gems/actionpack-7.1.3.4/lib/action_dispatch/middleware/executor.rb:14:in `call'\n/home/vscode/.gems/ruby/3.3.0/gems/actionpack-7.1.3.4/lib/action_dispatch/middleware/actionable_exceptions.rb:16:in `call'\n/home/vscode/.gems/ruby/3.3.0/gems/better_errors-2.10.1/lib/better_errors/middleware.rb:87:in `protected_app_call'\n/home/vscode/.gems/ruby/3.3.0/gems/better_errors-2.10.1/lib/better_errors/middleware.rb:82:in `better_errors_call'\n/home/vscode/.gems/ruby/3.3.0/gems/better_errors-2.10.1/lib/better_errors/middleware.rb:60:in `call'\n/home/vscode/.gems/ruby/3.3.0/gems/actionpack-7.1.3.4/lib/action_dispatch/middleware/debug_exceptions.rb:29:in `call'\n/home/vscode/.gems/ruby/3.3.0/gems/actionpack-7.1.3.4/lib/action_dispatch/middleware/show_exceptions.rb:31:in `call'\n/home/vscode/.gems/ruby/3.3.0/gems/railties-7.1.3.4/lib/rails/rack/logger.rb:37:in `call_app'\n/home/vscode/.gems/ruby/3.3.0/gems/railties-7.1.3.4/lib/rails/rack/logger.rb:24:in `block in call'\n/home/vscode/.gems/ruby/3.3.0/gems/activesupport-7.1.3.4/lib/active_support/tagged_logging.rb:135:in `block in tagged'\n/home/vscode/.gems/ruby/3.3.0/gems/activesupport-7.1.3.4/lib/active_support/tagged_logging.rb:39:in `tagged'\n/home/vscode/.gems/ruby/3.3.0/gems/activesupport-7.1.3.4/lib/active_support/tagged_logging.rb:135:in `tagged'\n/home/vscode/.gems/ruby/3.3.0/gems/activesupport-7.1.3.4/lib/active_support/broadcast_logger.rb:240:in `method_missing'\n/home/vscode/.gems/ruby/3.3.0/gems/railties-7.1.3.4/lib/rails/rack/logger.rb:24:in `call'\n/home/vscode/.gems/ruby/3.3.0/gems/actionpack-7.1.3.4/lib/action_dispatch/middleware/remote_ip.rb:92:in `call'\n/home/vscode/.gems/ruby/3.3.0/gems/actionpack-7.1.3.4/lib/action_dispatch/middleware/request_id.rb:28:in `call'\n/home/vscode/.gems/ruby/3.3.0/gems/rack-3.0.11/lib/rack/method_override.rb:28:in `call'\n/home/vscode/.gems/ruby/3.3.0/gems/rack-3.0.11/lib/rack/runtime.rb:24:in `call'\n/home/vscode/.gems/ruby/3.3.0/gems/activesupport-7.1.3.4/lib/active_support/cache/strategy/local_cache_middleware.rb:29:in `call'\n/home/vscode/.gems/ruby/3.3.0/gems/actionpack-7.1.3.4/lib/action_dispatch/middleware/executor.rb:14:in `call'\n/home/vscode/.gems/ruby/3.3.0/gems/actionpack-7.1.3.4/lib/action_dispatch/middleware/static.rb:25:in `call'\n/home/vscode/.gems/ruby/3.3.0/gems/rack-3.0.11/lib/rack/sendfile.rb:114:in `call'\n/home/vscode/.gems/ruby/3.3.0/gems/actionpack-7.1.3.4/lib/action_dispatch/middleware/host_authorization.rb:141:in `call'\n/home/vscode/.gems/ruby/3.3.0/gems/railties-7.1.3.4/lib/rails/engine.rb:536:in `call'\n/home/vscode/.gems/ruby/3.3.0/gems/railties-7.1.3.4/lib/rails/railtie.rb:226:in `public_send'\n/home/vscode/.gems/ruby/3.3.0/gems/railties-7.1.3.4/lib/rails/railtie.rb:226:in `method_missing'\n/home/vscode/.gems/ruby/3.3.0/gems/puma-6.4.2/lib/puma/configuration.rb:272:in `call'\n/home/vscode/.gems/ruby/3.3.0/gems/puma-6.4.2/lib/puma/request.rb:100:in `block in handle_request'\n/home/vscode/.gems/ruby/3.3.0/gems/puma-6.4.2/lib/puma/thread_pool.rb:378:in `with_force_shutdown'\n/home/vscode/.gems/ruby/3.3.0/gems/puma-6.4.2/lib/puma/request.rb:99:in `handle_request'\n/home/vscode/.gems/ruby/3.3.0/gems/puma-6.4.2/lib/puma/server.rb:464:in `process_client'\n/home/vscode/.gems/ruby/3.3.0/gems/puma-6.4.2/lib/puma/server.rb:245:in `block in run'\n/home/vscode/.gems/ruby/3.3.0/gems/puma-6.4.2/lib/puma/thread_pool.rb:155:in `block in spawn_thread'```

Copy link

@theiris6 theiris6 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Backend security implementation for PDF handling passes all tests.

  • The server-side validation and sanitization mechanisms successfully detect and reject malicious PDFs. I've confirmed the API component properly implements the scanning for JavaScript and other malicious content embedded in uploaded files.
    image

  • The server-side security layer provides robust protection against the identified vulnerability.
    It's approved. Good work and thanks for the opportunity to review.

Copy link

@atharv02-git atharv02-git left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello again @ibi420, as per my previous review on to the doubtfire-web, I can confirm the fix has been made, now let's move on to the backend fix, here are my reviews:

  1. The function def sanitize_pdf() inisde file_helper.rb which you created, clearly states that any malicious code injected in the form of a pdf is being sanitised and the payload free pdf is now being sent on OnTrack.
  2. I was also able to confirm the test_cases for the function you wrote can be seen inside the development.log:
    Screenshot (578)
    I can tell another vulnerability has been patched successfully, keep up the great work 🫡

@aNebula
Copy link

aNebula commented Jun 13, 2025

LGTM.
@ibi420 Please open an upstream PR against 9.x branch on doubtfire-lms/doubtfire-api. Remember to include a description, and may be even the video demo.

@aNebula aNebula closed this Jun 13, 2025
@aNebula aNebula reopened this Jun 13, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants