mirror of
				https://gitea.invidious.io/iv-org/shard-kemal.git
				synced 2024-08-15 00:53:36 +00:00 
			
		
		
		
	Only follow symlinks within configured static file handler directory
This adds an additional check to only follow symlinks that are within the configured public directory of a static file handler. This ensures a malicious user cannot link to any files outside of the public directory to prevent reading arbitrary files.
This commit is contained in:
		
							parent
							
								
									6e2714404d
								
							
						
					
					
						commit
						b86d761242
					
				
					 2 changed files with 37 additions and 0 deletions
				
			
		| 
						 | 
					@ -150,4 +150,34 @@ describe Kemal::StaticFileHandler do
 | 
				
			||||||
    response = handle HTTP::Request.new("GET", "/dir/index.html")
 | 
					    response = handle HTTP::Request.new("GET", "/dir/index.html")
 | 
				
			||||||
    response.headers["Access-Control-Allow-Origin"].should eq("*")
 | 
					    response.headers["Access-Control-Allow-Origin"].should eq("*")
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it "should not follow symlinks outside of the configured directory" do
 | 
				
			||||||
 | 
					    tempfile = File.tempfile("symlink", "txt")
 | 
				
			||||||
 | 
					    symlink_path = "#{__DIR__}/static/dir/symlink.txt"
 | 
				
			||||||
 | 
					    File.write tempfile.path, "my_super_secret"
 | 
				
			||||||
 | 
					    begin
 | 
				
			||||||
 | 
					      File.symlink(tempfile.path, symlink_path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      response = handle HTTP::Request.new("GET", "/dir/symlink.txt")
 | 
				
			||||||
 | 
					      response.body.should_not contain("my_super_secret")
 | 
				
			||||||
 | 
					      response.status_code.should eq(404)
 | 
				
			||||||
 | 
					    ensure
 | 
				
			||||||
 | 
					      File.delete symlink_path
 | 
				
			||||||
 | 
					      tempfile.delete
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it "should follow symlinks inside of the configured directory" do
 | 
				
			||||||
 | 
					    symlink_path = "#{__DIR__}/static/dir/symlink.txt"
 | 
				
			||||||
 | 
					    begin
 | 
				
			||||||
 | 
					      File.symlink("#{__DIR__}/static/dir/test.txt", symlink_path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      response = handle HTTP::Request.new("GET", "/dir/symlink.txt")
 | 
				
			||||||
 | 
					      response.status_code.should eq(200)
 | 
				
			||||||
 | 
					      response.body.should eq(File.read("#{__DIR__}/static/dir/test.txt"))
 | 
				
			||||||
 | 
					    ensure
 | 
				
			||||||
 | 
					      File.delete symlink_path
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -39,6 +39,13 @@ module Kemal
 | 
				
			||||||
                    end
 | 
					                    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      file_path = File.join(@public_dir, expanded_path)
 | 
					      file_path = File.join(@public_dir, expanded_path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      # prevent symlinks out of the public dir
 | 
				
			||||||
 | 
					      if File.symlink?(file_path) && !File.real_path(file_path).starts_with?(@public_dir)
 | 
				
			||||||
 | 
					        call_next(context)
 | 
				
			||||||
 | 
					        return
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      is_dir = Dir.exists? file_path
 | 
					      is_dir = Dir.exists? file_path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if request_path != expanded_path
 | 
					      if request_path != expanded_path
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue